你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

从后端使用 REST API

注册管理中所述,应用程序后端通常会发送通知,并可能执行注册管理。 由于 Azure SDK for Node 中已有用于Node.js的 REST 包装器,本部分演示 Java 中的示例。

发送通知

用于发送通知的 REST API 是 /yourHub/messages 上的简单 POST,具有特殊标头。 以平台本机格式发送通知时,正文是要发送的平台特定正文。 其他标头包括:

  • ServiceBusNotification-Format:指定在发送本机通知) 或“模板”时,平台 (发送模板通知。

  • ServiceBusNotification-Tags (可选) :指定标记 (或标记表达式) 定义目标注册集。 如果此标头不存在,通知中心将广播到所有注册。

特定于平台的功能支持其他标头,如 通知中心 REST API 文档中所述。

以下 Java 代码使用 Apache HttpClient) (向 Windows 应用商店应用发送本机通知:

public Notification createWindowsNotification(String body) {
    Notification n = new Notification();
    n.body = body;

    n.headers.put("ServiceBusNotification-Format", "windows");

    if (body.contains("<toast>"))
        n.headers.put("X-WNS-Type", "wns/toast");
    if (body.contains("<tile>"))
        n.headers.put("X-WNS-Type", "wns/tile");
    if (body.contains("<badge>"))
        n.headers.put("X-WNS-Type", "wns/badge");

    if (body.startsWith("<")) {
        n.contentType = ContentType.APPLICATION_XML;
    }

    return n;
}

public void sendNotification(Notification notification, String tagExpression) {
    HttpPost post = null;
    try {
        URI uri = new URI(endpoint + hubPath + "/messages"+APIVERSION);
        post = new HttpPost(uri);
        post.setHeader("Authorization", generateSasToken(uri));

        if (tagExpression != null && !"".equals(tagExpression)) {
            post.setHeader("ServiceBusNotification-Tags", tagExpression);
    }

        for (String header: notification.getHeaders().keySet()) {
            post.setHeader(header, notification.getHeaders().get(header));
        }

        post.setEntity(new StringEntity(notification.getBody()));
        HttpResponse response = httpClient.execute(post);

        if (response.getStatusLine().getStatusCode() != 201) {
            String msg = "";
            if (response.getEntity() != null && response.getEntity().getContent() != null) {
                msg = IOUtils.toString(response.getEntity().getContent());
            }
            throw new RuntimeException("Error: " + response.getStatusLine() + " body: "+msg);
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {
        if (post != null) post.releaseConnection();
    }
}

同样,以下代码发送模板通知:

public Notification createTemplateNotification(Map<String, String> properties) {
    Notification n = new Notification();
    StringBuffer buf = new StringBuffer();
    buf.append("{");
    for (Iterator<String> iterator = properties.keySet().iterator(); iterator.hasNext();) {
        String key = iterator.next();
        buf.append("\""+ key + "\":\""+properties.get(key)+"\"");
        if (iterator.hasNext()) buf.append(",");
    }
    buf.append("}");
    n.body = buf.toString();

    n.contentType = ContentType.APPLICATION_JSON;

    n.headers.put("ServiceBusNotification-Format", "template");

    return n;
}

有关将通知发送到其他平台的详细信息,请参阅 通知中心 REST API

创建和更新注册

创建和更新注册需要对注册 XML 格式进行序列化和反序列化。 创建注册 API 主题介绍了用于为每个平台) 创建不同类型的注册 (本机和模板的 XML 格式。

重要

XML 元素必须按显示的确切顺序排列。

下面是在 Java 中创建注册的示例,使用简单的字符串串联创建注册 XML 有效负载,并使用 Apache Digester 分析结果。 如前所述,任何 XML 序列化或反序列化方法都有效。

public Registration createRegistration(Registration registration) {
    HttpPost post = null;
    try {
        URI uri = new URI(endpoint + hubPath + "/registrations"+APIVERSION);
        post = new HttpPost(uri);
        post.setHeader("Authorization", generateSasToken(uri));

        StringEntity entity = new StringEntity(registration.getXml(),ContentType.APPLICATION_ATOM_XML);
        entity.setContentEncoding("utf-8");
        post.setEntity(entity);
        HttpResponse response = httpClient.execute(post);

        if (response.getStatusLine().getStatusCode() != 200)
            throw new RuntimeException("Error: " + response.getStatusLine());

        return Registration.parse(response.getEntity().getContent());
    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {
        if (post != null) post.releaseConnection();
    }
}

本机 Windows 注册的 getXml () 方法如下所示:

private static final String WNS_NATIVE_REGISTRATION = "<?xml version=\"1.0\" encoding=\"utf-8\"?><entry xmlns=\"http://www.w3.org/2005/Atom\"><content type=\"application/xml\"><WindowsRegistrationDescription xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.microsoft.com/netservices/2010/10/servicebus/connect\">{0}<ChannelUri>{1}</ChannelUri></WindowsRegistrationDescription></content></entry>";

public String getXml() {
    String xml = WNS_NATIVE_REGISTRATION.replaceFirst("\\{1\\}", channelUri.toString());
    xml = xml.replaceFirst("\\{0\\}", getTagsXml());
    return xml.toString();
}

可以从创建注册 API 主题中的示例轻松派生其他 注册 类型的方法。

响应包含创建结果,包括只读属性,例如 RegistrationIdETagExpirationTime。 以下代码示例使用 Apache Digester 分析结果:

public static Registration parse(InputStream content) throws IOException,
            SAXException {
    Digester digester = new Digester();
    digester.addObjectCreate("*/WindowsRegistrationDescription",
                WindowsRegistration.class);

    digester.addCallMethod("*/RegistrationId", "setRegistrationId", 1);
    digester.addCallParam("*/RegistrationId", 0);
    digester.addCallMethod("*/ETag", "setEtag", 1);
    digester.addCallParam("*/ETag", 0);
    digester.addCallMethod("*/ChannelUri", "setChannelUri", 1);
    digester.addCallParam("*/ChannelUri", 0);
    digester.addCallMethod("*/Tags", "setTagsFromString", 1);
    digester.addCallParam("*/Tags", 0);
    digester.addCallMethod("*/BodyTemplate", "setBodyTemplate", 1);
    digester.addCallParam("*/BodyTemplate", 0);
    digester.addCallMethod("*/WnsHeader", "addHeader", 2);
    digester.addCallParam("*/WnsHeader/Header", 0);
    digester.addCallParam("*/WnsHeader/Value", 1);

    return digester.parse(content);
}

Create 调用返回 registrationId,用于检索、更新或删除注册。

注意

前面的代码片段假定有一个名为 WindowsRegistrationDescription 的 Registration 子类。

可以通过在 /yourhub/registrations/{registrationId} 上发出 PUT 调用来更新注册。 If-Match 标头用于提供 ETag (支持乐观并发) 或仅提供“*”以始终覆盖。 如果 If-Match 标头不存在,则操作将执行“upsert” (始终覆盖当前注册,或者在提供的 registrationId 上创建一个(如果不存在) )。 例如:

public Registration updateRegistration(Registration registration) {
    HttpPut put = null;
    try {
        URI uri = new URI(endpoint + hubPath + "/registrations/"+registration.getRegistrationId()+APIVERSION);
        put = new HttpPut(uri);
        put.setHeader("Authorization", generateSasToken(uri));
        put.setHeader("If-Match", registration.getEtag()==null?"*":"W/\""+registration.getEtag()+"\"");

        put.setEntity(new StringEntity(registration.getXml(),ContentType.APPLICATION_ATOM_XML));
        HttpResponse response = httpClient.execute(put);

        if (response.getStatusLine().getStatusCode() != 200)
            throw new RuntimeException("Error: " + response.getStatusLine());

        return Registration.parse(response.getEntity().getContent());
    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {
        if (put != null) put.releaseConnection();
    }
}

删除注册 是类似的操作。

检索注册

检索注册时,请在 /registrations/{registrationId} 上发出 GET 调用。 检索以下 REST API 中指定的注册集合:

然后,可以选择指定 $top 参数,以限制返回的注册数。 如果存在该查询的更多注册,则返回 X-MS-ContinuationToken 标头,你可以将该标头传递给后续调用,以便继续检索剩余的注册。 另请注意,正文的格式现在是 XML Atom 源,如前面提到的 API 主题所示。

minterastlib 的以下 Java 代码检索具有 标记的所有注册:

    private CollectionResult retrieveRegistrationByTag() {
        String queryUri = endpoint + hubPath + "/tags/"+tag+"/registrations"+APIVERSION;
    HttpGet get = null;
        try {
            URI uri = new URI(queryUri);
            get = new HttpGet(uri);
            get.setHeader("Authorization", generateSasToken(uri));
    
            HttpResponse response = httpClient.execute(get);
    
            if (response.getStatusLine().getStatusCode() != 200)
                throw new RuntimeException("Error: " + response.getStatusLine());
    
            CollectionResult result = Registration.parseRegistrations(response.getEntity().getContent());
            Header contTokenHeader = response.getFirstHeader("X-MS-ContinuationToken");
            if (contTokenHeader !=null) {
                result.setContinuationToken(contTokenHeader.getValue());
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (get != null) get.releaseConnection();
        }
    }

在此代码中,CollectionResult 封装了一组注册以及可选的继续标记。

以下代码使用 Apache Digester

public static CollectionResult parseRegistrations(InputStream content)
            throws IOException, SAXException {
    Digester digester = new Digester();

    // add all rules for parsing single registrations
    digester.addObjectCreate("feed", CollectionResult.class);
    digester.addSetNext("*/WindowsRegistrationDescription", "addRegistration");
    // add rules for other types of registrations (if required)

    return digester.parse(content);
}