如何将用户上下文 object 传递给异步 Jetty HTTP 客户端的响应回调?

How to pass user context object to the response callback of async Jetty HTTP client?

通过 Google Firebase Cloud Messaging 向单个收件人发送通知时,有时会返回一个响应(200 + error:MissingRegistration200 + error:InvalidRegistration200 + error:NotRegistered),这需要删除该消息的令牌收件人(因为她重新安装了 Android 应用程序并且令牌已更改)。

我的问题是:

如何将该字符串(FCM 令牌)传递回 non-blocking Jetty HTTP client 的响应回调?

目前我的解决方法是将自定义 HTTP header 添加到我的请求中:

X-token: APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...

然后我在响应回调中检索它。但这是一个 hack,因为 FCM 没有指定这样的 header 而且我还需要传递更多自定义数据(我的应用程序中的内部用户 ID)。

这里是 my current source code 和自定义 HTTP header,请问如何更改?

private static final String FCM_URL                  = "https://fcm.googleapis.com/fcm/send";
private static final String FCM_KEY                  = "key=REPLACE_BY_YOUR_KEY";
private static final String FCM_RESULTS              = "results";
private static final String FCM_ERROR                = "error";
private static final String FCM_NOT_REGISTERED       = "NotRegistered";
private static final String FCM_MISSING_REGISTRATION = "MissingRegistration";
private static final String FCM_INVALID_REGISTRATION = "InvalidRegistration";

private static final String FCM_X_TOKEN              = "X-token";
private static final String TOKEN                    = "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...";

private static final Map<String, Object> REQUEST      = new HashMap<>();
private static final Map<String, Object> NOTIFICATION = new HashMap<>();
private static final Map<String, Object> DATA         = new HashMap<>();

static {
    REQUEST.put("to", TOKEN);
    REQUEST.put("notification", NOTIFICATION);
    REQUEST.put("data", DATA);
    NOTIFICATION.put("body", "great match!");
    NOTIFICATION.put("title", "Portugal vs. Denmark");
    NOTIFICATION.put("icon", "myicon");
    DATA.put("Nick", "Mario");
    DATA.put("Room", "PortugalVSDenmark");
}

private static final SslContextFactory sFactory = new SslContextFactory();
private static final HttpClient sHttpClient = new HttpClient(sFactory);
private static final BufferingResponseListener sFcmListener = new BufferingResponseListener() {
    @Override
    public void onComplete(Result result) {
        if (!result.isSucceeded()) {
            System.err.println(result.getFailure());
            return;
        }

        String body = getContentAsString(StandardCharsets.UTF_8);

        try {
            Map<String, Object> resp = (Map<String, Object>) JSON.parse(body);
            Object[] results = (Object[]) resp.get(FCM_RESULTS);
            Map map = (Map) results[0];
            String error = (String) map.get(FCM_ERROR);
            System.out.printf("error: %s\n", error);
            if (FCM_NOT_REGISTERED.equals(error) ||
                FCM_MISSING_REGISTRATION.equals(error) ||
                FCM_INVALID_REGISTRATION.equals(error)) {
                String token = result.getRequest().getHeaders().get(FCM_X_TOKEN);
                System.out.printf("TODO delete invalid FCM token from the database: %s\n", token);
            }
        } catch (Exception ex) {
            System.err.println(ex);
        }
    }
};

public static void main(String[] args) throws Exception {
    sHttpClient.start();
    sHttpClient.POST(FCM_URL)
        .header(HttpHeader.AUTHORIZATION, FCM_KEY)
        .header(HttpHeader.CONTENT_TYPE, "application/json")
        .header(FCM_X_TOKEN, TOKEN) // Workaround, how to improve?
        .content(new StringContentProvider(JSON.toString(REQUEST)))
        .send(sFcmListener);
}

您想将令牌设置为请求 属性 并取回它:

httpClient.POST(url)
        .attribute(key, token)
        ...
        .send(new BufferingResponseListener() {
            @Override
            public void onComplete(Result result) {
                Object token = result.getRequest().getAttribute(key);
                ...
            }
        });