4

我最近开始使用 Play!用于编写 Java Web 应用程序的框架 (v2.0.4)。在我的大多数控制器中,我遵循暂停 HTTP 请求的范例,直到实现 Web 服务响应的承诺。一旦承诺兑现,我会返回一个AsyncResult. 这是我的大部分操作的样子(省略了一堆代码):

public static Result myActionMethod() {

    Promise<MyWSResponse> wsResponse;
    // Perform a web service call that will return the promise of a MyWSResponse...

    return async(wsResponse.map(new Function<MyWSResponse, Result>() {
        @Override
        public Result apply(MyWSResponse response) {

            // Validate response...
            return ok(myScalaViewTemplate.render(response.data()));
        }
    }));
}

我现在正在尝试使我的应用程序国际化,但是当我尝试从async方法呈现模板时遇到以下错误:

[error] play - Waiting for a promise, but got an error: There is no HTTP Context available from here.
java.lang.RuntimeException: There is no HTTP Context available from here.
    at play.mvc.Http$Context.current(Http.java:27) ~[play_2.9.1.jar:2.0.4]
    at play.mvc.Http$Context$Implicit.lang(Http.java:124) ~[play_2.9.1.jar:2.0.4]
    at play.i18n.Messages.get(Messages.java:38) ~[play_2.9.1.jar:2.0.4]
    at views.html.myScalaViewTemplate$.apply(myScalaViewTemplate.template.scala:40) ~[classes/:na]
    at views.html.myScalaViewTemplate$.render(myScalaViewTemplate.template.scala:87) ~[classes/:na]
    at views.html.myScalaViewTemplate.render(myScalaViewTemplate.template.scala) ~[classes/:na]

简而言之,我在我的视图模板中有一个消息包查找,一些 Play!代码正在尝试访问原始 HTTP 请求并检索accept-languages标头,以便知道要使用哪个消息包。但似乎无法从异步方法访问 HTTP 请求。

我可以看到几种(不令人满意的)方法来解决这个问题:

  1. 回到“每个请求一个线程”范例,让线程阻塞等待响应。
  2. 找出在控制器级别使用哪种语言,并将该选择输入我的模板。

我也怀疑这可能不是主干上的问题。我知道 2.0.4 中存在类似的问题,即无法访问或修改Session最近修复的对象。但是我暂时停留在 2.0.4 上,那么有没有更好的方法可以解决这个问题?

4

1 回答 1

5

会在这里回答我自己的问题。我的一位同事最终找到了一个简单的解决方案:

public static Result myActionMethod() {

    final Context ctx = ctx(); // (1)
    Promise<MyWSResponse> wsResponse;
    // Perform a web service call that will return the promise of a MyWSResponse...

    return async(wsResponse.map(new Function<MyWSResponse, Result>() {
        @Override
        public Result apply(MyWSResponse response) {

            Context.current.set(ctx); // (2)

            // Validate response...
            return ok(myScalaViewTemplate.render(response.data()));
        }
    }));
}
  1. 在操作开始时获取对 HTTP 上下文的引用
  2. async进入块后在 ThreadLocal 中恢复它
于 2012-11-30T17:02:05.473 回答