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

时间:2017-06-30 08:58:09

标签: nullpointerexception jetty firebase-cloud-messaging future jetty-9

在我在GitHub准备的Firebase Cloud Messaging by Googlenon-blocking Jetty HTTP client的帮助下尝试使用a simple test case

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: %s\n", 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,即使the Google FCM endpoint是众所周知的主机:

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: %s\n", 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,为什么?

1 个答案:

答案 0 :(得分:1)

添加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: %s\n", 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: %s\n", 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);
}

我还有一个问题是how to retrieve the invalid FCM token that I have used in the Jetty HTTP client request,所以我可以在数据库中将其从响应中删除...