如何避免"java.lang.RuntimeException: There is no HTTP Context available from here"?
How to avoid "java.lang.RuntimeException: There is no HTTP Context available from here"?
我在发送有关用户操作的通知电子邮件时遇到 Play Framework 2.5 异常。这是代码:
public class IpnListener extends Controller {
@Inject
private Notif notif;
@Inject
private WSClient ws;
public CompletionStage<Result> validate() {
return ws.url(/*...*/)
.thenApply(response -> {
/* do some validations */
notif.send(ctx(), notification, user.getEmail());
});
}
}
Notif
class.
public class Notif {
@Inject
private MailerClient mailerClient;
@Inject
private HttpExecutionContext executionContext;
public void send(Http.Context context, Notification notification, String target) {
/* create an email with template*/
CompletableFuture.runAsync(() -> {
try {
mailerClient.send(email);
}
catch (Exception e) {
e.printStackTrace();
}
},
executionContext.current());
}
}
然后我随机得到这个异常:
java.lang.RuntimeException: There is no HTTP Context available from here.
at play.mvc.Http$Context.current(Http.java:62)
at play.mvc.Controller.ctx(Controller.java:27)
at controllers.listeners.IpnListener.lambda$validate[=13=](IpnListener.java:69)
at services.payment.PayPal$Request.lambda$verify[=13=](PayPal.java:201)
at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:616)
at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:591)
at java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:457)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
java.lang.RuntimeException: There is no HTTP Context available from here.
at play.mvc.Http$Context.current(Http.java:62)
at play.mvc.Controller.ctx(Controller.java:27)
at controllers.listeners.IpnListener.lambda$validate[=13=](IpnListener.java:69)
at services.payment.PayPal$Request.lambda$verify[=13=](PayPal.java:201)
at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:616)
at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:591)
at java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:457)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
我正在考虑将 ctx()
值保存在这样的变量中,但我不确定它的生命周期:
public class IpnListener extends Controller {
@Inject
private Notif notif;
@Inject
private WSClient ws;
public CompletionStage<Result> validate() {
Http.Context context = ctx();
return ws.url(/*...*/)
.thenApply(response -> {
/* do some validations */
notif.send(context, notification, user.getEmail());
});
}
}
你需要
@Inject HttpExecutionContext ec;
into your controller. On the thenApply() call, supply ec.current() as the executioner.
.thenApply(response -> {
}, ex.current());
从 WSClient
调用的 thenApply()
方法中没有可用的 HTTP 上下文,因此我不得不将 HttpExecutionContext
与 thenApplyAsync()
一起使用。
public class IpnListener extends Controller {
@Inject
private Notif notif;
@Inject
private WSClient ws;
@Inject
private HttpExecutionContext httpExecutionContext;
public CompletionStage<Result> validate() {
Http.Context context = ctx();
return ws.url(/*...*/)
.thenApplyAsync(response -> {
/* do some validations */
notif.send(context, notification, user.getEmail());
},
httpExecutionContext.current());
}
}
我在发送有关用户操作的通知电子邮件时遇到 Play Framework 2.5 异常。这是代码:
public class IpnListener extends Controller {
@Inject
private Notif notif;
@Inject
private WSClient ws;
public CompletionStage<Result> validate() {
return ws.url(/*...*/)
.thenApply(response -> {
/* do some validations */
notif.send(ctx(), notification, user.getEmail());
});
}
}
Notif
class.
public class Notif {
@Inject
private MailerClient mailerClient;
@Inject
private HttpExecutionContext executionContext;
public void send(Http.Context context, Notification notification, String target) {
/* create an email with template*/
CompletableFuture.runAsync(() -> {
try {
mailerClient.send(email);
}
catch (Exception e) {
e.printStackTrace();
}
},
executionContext.current());
}
}
然后我随机得到这个异常:
java.lang.RuntimeException: There is no HTTP Context available from here.
at play.mvc.Http$Context.current(Http.java:62)
at play.mvc.Controller.ctx(Controller.java:27)
at controllers.listeners.IpnListener.lambda$validate[=13=](IpnListener.java:69)
at services.payment.PayPal$Request.lambda$verify[=13=](PayPal.java:201)
at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:616)
at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:591)
at java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:457)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
java.lang.RuntimeException: There is no HTTP Context available from here.
at play.mvc.Http$Context.current(Http.java:62)
at play.mvc.Controller.ctx(Controller.java:27)
at controllers.listeners.IpnListener.lambda$validate[=13=](IpnListener.java:69)
at services.payment.PayPal$Request.lambda$verify[=13=](PayPal.java:201)
at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:616)
at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:591)
at java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:457)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
我正在考虑将 ctx()
值保存在这样的变量中,但我不确定它的生命周期:
public class IpnListener extends Controller {
@Inject
private Notif notif;
@Inject
private WSClient ws;
public CompletionStage<Result> validate() {
Http.Context context = ctx();
return ws.url(/*...*/)
.thenApply(response -> {
/* do some validations */
notif.send(context, notification, user.getEmail());
});
}
}
你需要
@Inject HttpExecutionContext ec;
into your controller. On the thenApply() call, supply ec.current() as the executioner.
.thenApply(response -> {
}, ex.current());
从 WSClient
调用的 thenApply()
方法中没有可用的 HTTP 上下文,因此我不得不将 HttpExecutionContext
与 thenApplyAsync()
一起使用。
public class IpnListener extends Controller {
@Inject
private Notif notif;
@Inject
private WSClient ws;
@Inject
private HttpExecutionContext httpExecutionContext;
public CompletionStage<Result> validate() {
Http.Context context = ctx();
return ws.url(/*...*/)
.thenApplyAsync(response -> {
/* do some validations */
notif.send(context, notification, user.getEmail());
},
httpExecutionContext.current());
}
}