4

私はPlayFrameworkのバージョン 2.0.2 を使用しており、http 結果のポスト フィルターplay.mvc.Actionを実装するプレイを作成しようとしています。

アクターを前処理に使用する例は、play docsで説明されています。

しかし、私が達成したいことは少し異なります。する必要がある:

  • 取るplay.mvc.Result
  • 体を取り出す
  • 体に変換を適用する
  • 次に、新しい結果を作成します。

Resultインターフェイスは http body を公開しません。また、特定のサブクラス ( SimpleResult、または などAsyncResult) があると仮定しても、メッセージ本文を抽出する方法がわかりません。

私の具体的な使用例は、結果の本文を GZip し、正しい「Content-Encoding」ヘッダーを追加するフィルターです。GZipドキュメントでの認証の実装方法と同様に、注釈を追加することで、このフィルターを既存のコントローラーに適用できるようにしたいと考えています。

以下は私がやろうとしていることの例です

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);
   }
}
4

2 に答える 2

4

http の結果を変更する際にも同様のケースがありました。Java でこれに対処するための私のアプローチを共有したいと思います。

Play 2.0.3 の Scala ソース コードを調べたところ、 Java でクラスplay.core.j.JavaResultExtractorのレスポンス ボディ、Cookie、ヘッダー、およびステータスを取得し、レスポンス ボディの内容を書き込むことができることがわかりました。Resultplay.core.j.JavaResults

それにもかかわらず、現在のレスポンスボディを変更されたボディに簡単に置き換える方法はまだわかりません。おそらく、これを Scala の実装で扱う方が簡単かもしれませんが、それでも Scala は難解すぎて読めないことがわかりました :-(

私が見つけた方法play.mvc.Results.Statusは、 を使用しplay.core.j.JavaResultsてコンテンツ本文を記述する方法を確認することです。私が言及したクラスはok()、 、notFound()、 、およびJava のクラスで生成するforbidden()他の同様のメソッドの中心です。このクラスの実装は次のようになります: (読みやすくするために Scala クラスをリファクタリングしました)ResultController

// 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インターフェースも実装する必要があります。全体として、私が言ったことからコードを実装すると、次のようになります。

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))
            );
    }

    // ...
}

上記の実装により、http の結果を変更できます。これがあなたの特定のユースケースに役立つことを願っています。

乾杯!

アップデート

上記のコードは、http の結果を変更する際のほとんどのユースケースを解決できます。あなたの特定のケース、つまり gzip 応答では、gzip された本体が in に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()
            );
        }

}

私の更新前の私の実装に基づいて、コードにこれを行う方法を理解できます。もう実装する必要はなくplay.api.mvc.Content、応答で適切な content-type を返すようにしてください。

幸せなコーディング:-)

于 2012-09-17T03:09:01.517 に答える
3

私の知る限り、掘り下げた後、result.getWrappedResult();を使用して応答の本文を取得できます。メソッドを含む にplay.api.mvc.Result(一般的に)キャストできる を返します。play.api.mvc.SimpleResultbody()

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

次に、Enumerator docを読むことをお勧めします。今のところ、私はこれらがどのように機能するかを理解していません:-)。

これが少しお役に立てば幸いです...

于 2012-08-31T09:37:48.020 に答える