修改PlayFramework中http结果的正文

时间:2012-08-30 02:42:22

标签: playframework playframework-2.0

我正在使用PlayFramework版本2.0.2,我正在尝试创建一个游戏play.mvc.Action来为http结果实现后置过滤器

使用actor进行预处理的示例在play docs

中进行了解释

然而,我想要达到的目标有点不同。我需要:

  • 选择play.mvc.Result
  • 提取身体
  • 将变换应用于身体
  • 然后创建一个新结果。

Result界面不会公开http正文,甚至假设你有特定的子类(比如SimpleResultAsyncResult)我不是确定如何提取邮件正文。

我的具体用例是GZip结果体并添加正确的“Content-Encoding”标头的过滤器。我希望能够通过添加注释来将此GZip过滤器应用于任何现有的Controller,类似于在文档中实现身份验证的方式。

下面是我想要做的一个例子

public class Compress {
  @With(GZipResult.class)
  public @interface GZip {
  }

  public static class GZipResult extends Action<GZip> {
    @Override
    public Result call(Http.Context ctx) throws Throwable {
      Result result = delegate.call(ctx);
      if (requestSupportsGZip(ctx) {
         result = extractAndGZipResult(result); //how to extract http body?
      }
      return result;
    }
  }
}

可以用作

@Compress.GZip
class MyController extends Controller {
   public static Result index() {
      return ok(someHtml);
   }
}

2 个答案:

答案 0 :(得分:4)

我在修改http结果时遇到了类似的情况。我想分享我在Java中处理这个问题的方法。

在检查Play 2.0.3的Scala源代码后,我发现play.core.j.JavaResultExtractor可以检索Java中Result类的响应正文,cookie,标题和状态{{1} }可以写出响应体的内容。

尽管如此,我仍然不知道如何以简单的方式用修改后的身体替换当前的反应体。也许用Scala实现处理这个会更容易,但我仍然发现Scala太神秘了: - (

我找到的方法是查看如何实现play.core.j.JavaResults,它使用play.mvc.Results.Status来编写内容正文。我提到的课程是play.core.j.JavaResultsok()notFound()的核心,以及在Java中forbidden()类中生成Result的其他类似方法。这个类的实现如下所示:(重构Scala类以提高可读性)

Controller

如果您希望实现上述代码,还需要实现// scala classes import play.api.mvc.Codec; import play.api.mvc.Content; import play.core.j.JavaResults; // ... public static class Status implements Result { final private play.api.mvc.Result wrappedResult; // ... // there are a lot of constructors for this class to reference from // this particular constructor is the general approach for most cases public Status(play.api.mvc.Results.Status status, Content content, Codec codec) { // ... wrappedResult = status.apply( content, JavaResults.writeContent(codec), JavaResults.contentTypeOf(content.contentType() + "; charset=" + codec.charset()) ); } } 接口。总而言之,从我说的内容中实现你的代码看起来像这样:

play.api.mvc.Content

通过上面的实现,我可以修改http结果。我希望这可以帮助您完成特定的用例。

干杯!

<强>

更新

上面的代码可以解决修改http结果的大多数用例。你的特殊情况,即gzipping响应,需要一种替代方法,因为gzipped主体位于import play.api.mvc.Codec; import play.api.mvc.Content; import play.core.j.JavaResultExtractor; import play.core.j.JavaResults; // ... public static class GZipResult extends Action<GZip> { @Override public Result call(Http.Context ctx) throws Throwable { Result result = delegate.call(ctx); if (requestSupportsGZip(ctx)) { // copy parts of current response final int statusCode = JavaResultExtractor.getStatus(result); final Map<String,String> headers = JavaResultExtractor.getHeaders(result); final byte[] body = JavaResultExtractor.getBody(result); // create a gzip result result = new GZipResult(statusCode, new String(body), headers.get("Content-Type")); // add appropriate headers here // ... } return result; } } private static class GZipResult implements Result { final private play.api.mvc.Result wrappedResult; public GZipResult(final int StatusCode, final String content, final String contentType) { if(content == null) throw new NullPointerException("null content"); // i guess this is the good place in transforming the content body String gzippedContent = someMethodToGzipContent(content); this.wrappedResult = JavaResults.Status(statusCode).apply( // implement the play.api.mvc.Content interface new Content() { @Override public String body() { return gzippedContent; } @Override public String contentType() { return contentType; } }, JavaResults.writeContent(Codec.utf_8), JavaResults.contentTypeOf(contentType)) ); } // ... } 而不是byte[]String类还提供了处理play.mvc.Results.Status的方法。实现如下:

byte[]

您可以在我的更新之前根据我的实现了解如何对代码执行此操作。请注意,您不再需要实现// scala classes import play.core.j.JavaResults; // ... public static class Status implements Result { final private play.api.mvc.Result wrappedResult; // ... public Status(play.api.mvc.Results.Status status, byte[] content) { // ... wrappedResult = status.apply( content, JavaResults.writeBytes(), JavaResults.contentTypeOfBytes() ); } } ,并确保在响应中返回适当的内容类型。

快乐编码: - )

答案 1 :(得分:3)

AFAIK,经过一番挖掘后,您可以使用result.getWrappedResult()获取回复的正文;它返回一个play.api.mvc.Result,可以(通常)转换为包含play.api.mvc.SimpleResult方法的body()

play.api.mvc.SimpleResult wrappedResult = (play.api.mvc.SimpleResult) result.getWrappedResult();
Enumerator body = wrappedResult.body();

然后,我建议你阅读Enumerator doc;目前,我还没弄清楚这些事情是如何运作的: - )。

希望这对你有所帮助......