尝试使用 Jetty 异步 HTTP 客户端时出现 NPE
NPE when trying to use Jetty async HTTP client
尝试使用我在 GitHub -
准备的 Firebase Cloud Messaging by Google with the help of non-blocking Jetty HTTP client in 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.access00(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.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
,为什么?
添加 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);
}
我还有一个悬而未决的问题是 ,这样我就可以在回复时从我的数据库中删除它...
尝试使用我在 GitHub -
准备的 Firebase Cloud Messaging by Google with the help of non-blocking Jetty HTTP client in 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.access00(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.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
,为什么?
添加 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);
}
我还有一个悬而未决的问题是