尝试使用 Jetty 异步 HTTP 客户端时的 NPE



当我在GitHub上准备的一个简单的测试用例中,在非阻塞Jetty HTTP客户端的帮助下尝试使用Google的Firebase Cloud Messaging 时 -

private static final HttpClient sHttpClient = new HttpClient();
private static final Response.ContentListener sFcmListener = new Response.ContentListener() {
    @Override
    public void onContent(Response response, ByteBuffer content) {
        if (response.getStatus() != 200) {
            return;
        }
        String body = StandardCharsets.UTF_8.decode(content).toString();
        System.out.printf("onContent: %sn", body);
        Map<String, Object> resp = (Map<String, Object>) JSON.parse(body);
        try {
            Object[] results = (Object[]) resp.get(FCM_RESULTS);
            Map result = (Map) results[0];
            String error = (String) result.get(FCM_ERROR);
            if (FCM_NOT_REGISTERED.equals(error)) {
                // TODO delete invalid FCM token from the database
            }
        } catch (Exception ignore) {
        }
    }
};
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")
        .content(new StringContentProvider(JSON.toString(REQUEST)))
        .onResponseContent(sFcmListener)
        .send();
}

但不幸的是,NPE 的执行立即失败:

2017-06-30 10:46:41.312:INFO::main: Logging initialized @168ms to org.eclipse.jetty.util.log.StdErrLog
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.NullPointerException
    at org.eclipse.jetty.client.util.FutureResponseListener.getResult(FutureResponseListener.java:118)
    at org.eclipse.jetty.client.util.FutureResponseListener.get(FutureResponseListener.java:101)
    at org.eclipse.jetty.client.HttpRequest.send(HttpRequest.java:682)
    at de.afarber.fcmnotregistered.Main.main(Main.java:68)
Caused by: java.lang.NullPointerException
    at org.eclipse.jetty.io.ssl.SslClientConnectionFactory.newConnection(SslClientConnectionFactory.java:59)
    at org.eclipse.jetty.client.AbstractHttpClientTransport$ClientSelectorManager.newConnection(AbstractHttpClientTransport.java:191)
    at org.eclipse.jetty.io.ManagedSelector.createEndPoint(ManagedSelector.java:420)
    at org.eclipse.jetty.io.ManagedSelector.access$1600(ManagedSelector.java:61)
    at org.eclipse.jetty.io.ManagedSelector$CreateEndPoint.run(ManagedSelector.java:599)
    at org.eclipse.jetty.util.thread.Invocable.invokePreferred(Invocable.java:128)
    at org.eclipse.jetty.util.thread.Invocable$InvocableExecutor.invoke(Invocable.java:222)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:294)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:199)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:672)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:590)
    at java.lang.Thread.run(Thread.java:745)

请问为什么会这样?

更新:

我已经切换到使用 BufferingResponseListener 并且 NPE 消失了,但现在程序打印java.net.NoRouteToHostException: No route to host即使 Google FCM 端点是众所周知的主机:

private static final HttpClient sHttpClient = new HttpClient();
private static final BufferingResponseListener sFcmListener = new BufferingResponseListener() {
    @Override
    public void onComplete(Result result) {
        if (!result.isSucceeded()) {
            System.err.println(result.getFailure()); // No route to host
            return;
        }
        String body = getContentAsString(StandardCharsets.UTF_8);
        System.out.printf("onContent: %sn", body);
        Map<String, Object> resp = (Map<String, Object>) JSON.parse(body);
        try {
            Object[] results = (Object[]) resp.get(FCM_RESULTS);
            Map map = (Map) results[0];
            String error = (String) map.get(FCM_ERROR);
            if (FCM_NOT_REGISTERED.equals(error)) {
                // TODO delete invalid FCM token from the database
            }
        } 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")
        .content(new StringContentProvider(JSON.toString(REQUEST)))
        .send(sFcmListener);
}

我尝试的任何FCM_URL值都会得到No route to host,为什么?

添加SslContextFactory对我有帮助:

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);
        System.out.printf("onComplete: %sn", body);
        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: %sn", error);
            if (FCM_NOT_REGISTERED.equals(error) ||
                FCM_MISSING_REGISTRATION.equals(error) ||
                FCM_INVALID_REGISTRATION.equals(error)) {
                // TODO delete invalid FCM token from the database
            }
        } 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")
        .content(new StringContentProvider(JSON.toString(REQUEST)))
        .send(sFcmListener);
}

我仍然悬而未决的问题是如何检索我在 Jetty HTTP 客户端请求中使用的无效 FCM 令牌,以便我可以在响应时将其从我的数据库中删除......

相关内容

  • 没有找到相关文章

最新更新