2013-11-04 23 views
12

JerseyクライアントからJerseyサーバーにファイルを送信して戻す簡単なJerseyアプリケーションを作成しようとしています。ただし、ファイルはクライアントからサーバーへの途中でエンコードされているように見えますが、それ以外の方法ではエンコードされていないようです。私はこの行動をどう変えることができるのだろうか。Jerseyを使用して応答メッセージ本体のGZip圧縮を行う方法

私は単純な例でこれをテストしています:

public class GZipEncodingTest extends JerseyTest { 

    private static final String PATH = "/"; 
    private static final String QUESTION = "foo", ANSWER = "bar"; 
    private static final String ENCODING_GZIP = "gzip"; 

    @Path(PATH) 
    public static class MyResource { 
    @POST 
    public Response handle(String question) throws IOException { 
     assertEquals(QUESTION, question); 
     return Response.ok(ANSWER).build(); // (1) 
    } 
    } 

    @Override 
    protected Application configure() { 
    enable(TestProperties.LOG_TRAFFIC); 
    enable(TestProperties.DUMP_ENTITY); 
    return new ResourceConfig(MyResource.class, GZipEncoder.class); 
    } 

    @Override 
    @SuppressWarnings("unchecked") 
    protected void configureClient(ClientConfig config) { 
    config.register(new EncodingFeature(ENCODING_GZIP, GZipEncoder.class)); 
    } 

    @Test 
    public void testHeaders() throws Exception { 
    Response response = target().path(PATH).request().post(Entity.text(QUESTION)); 
    assertEquals(ANSWER, response.readEntity(String.class)); 
    } 
} 

ログインダンプから、私が意図したとおりに要求であると言うことができる:コンテンツのエンコーディングは、ヘッダでシグナリング要求メッセージ本体に適用されます。 Accept-Encodingも設定されています。サーバーは、適用されたgzip圧縮を理解し、要求メッセージ本文を解凍します。ただし、クライアントがgzipレスポンスを受け入れ、応答メッセージ本文を非圧縮形式で送信するという事実は無視されます。

私はResponse -builderチェーンに(1)ラインencoding(ENCODING_GZIP)を追加すると、私は私が探しています結果を得ます。ただし、要求で許容可能とマークされている場合にのみエンコードを適用したいと思います。さらに、この機能は、特定のレスポンスだけでなく幅広く連携したいと考えています。

public class GZipWriterInterceptor implements WriterInterceptor { @Override public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { context.getHeaders().add(HttpHeaders.CONTENT_ENCODING, ENCODING_GZIP); context.proceed(); } } 

が、私は、これは、不必要なボイラープレートであることを確信しています:

私はもちろんWriterInterceptorを使って手動で、このような機能を追加することができます。

EncodingFeatureは、クライアントライブラリの一部であるようです。私は基本的に、リクエストがaccept-encodingを使ってエンコードを提案したときに、Jerseyサーバーがgzipとしてデータをエンコードできるようにしたいと考えています。

ウェブ上でソリューションを検索しようとすると、十分に見つけられます。それらのほとんどはJersey 1に関するものです.GrizzlyServerにリスナーを追加することをお勧めします(JAX-RSではなくJersey固有のものでしょうか?)。私は上の人々ことがわかっ

  • org.glassfish.grizzly.http.GZipContentEncoding
  • org.glassfish.jersey.message.GZipEncoder
  • org.glassfish.grizzly.compression.zip.GZipEncoder
  • org.glassfish.grizzly.compression.zip.GZipDecoder
  • org.glassfish.grizzly.compression.zip.GZipFilter

:その後のGZIPエンコーディングを示唆ジャージー2依存関係ツリー内のたくさんのクラスがありますウェブはそれらのどれかを使ってあなたにもお勧めしますgh私はorg.glassfish.jerseyが実際のジャージーの依​​存関係であるので正しい選択と思われると思っています。関連するライブラリのApacheConnectorにあるものについては言及しません。私は実際にどちらを使うべきか分かりません。

+0

http://stackoverflow.com/questions/19751014/gzip-encoding-in-jersey-2-grizzly –

+0

私の問題は実際にはもう少し複雑です。私はgzipエンコーディングを再構築したかったのです。私はここで私の質問を再作成しました:http://stackoverflow.com/questions/19794014/why-does-jersey-swallow-my-content-encoding-header –

+0

私はまだこの問題に*公式のソリューション*を再構築しようとしていますGZipの例を使用してください。しかし、私はそれだけではなく、他の方法で動作します。あなたが提案するソリューションは、正直言って私にハックのように見えます。 –

答えて

16

私はジャージーの図書館を通して見ました。サーバ側のために、以下の構成が必要である:CONVERS下

@Override 
@SuppressWarnings("unchecked") 
protected Application configure() { 
    ResourceConfig resourceConfig = new ResourceConfig(MyResource.class); 
    EncodingFilter.enableFor(resourceConfig, GZipEncoder.class); 
    return resourceConfig; 
} 

、所与ResourceConfigEncodingFilter、指定GZipEncoderレジスタEncodingFilter#enableFor(ResourceConfig.Class<? extends ContentEncoder>[])

登録時にこの迂回路の背後にあるのは、エンコードが2つの段階で行われる必要があるという事実にあります。まず、EncodingFilter(実際にはContainerResponseFilter)は、Content-Encodinggzipに設定して応答のヘッダーを変更します。同時に、このストリームが作成される前にフィルタが呼び出されるため、フィルタはメッセージ本文のエンティティストリームを変更できません。したがって、ストリームの変更は、フィルタの処理後およびエンティティストリームの作成後にトリガーされるWriterInterceptorによって処理する必要があります。GZipEncoderを登録すると、 Content-Encodingヘッダーは、サーバーの作成とは独立して発生するクライアントによってgzipに設定されます。

私が 'GZipWriterInterceptor'で与えた例は、基本的に実装されていないバージョンのEncodingFilterです。もちろん、ヘッダーはフィルターで設定し、インターセプターでは設定しないでください。それsays in the documentation

フィルタが主に要求及びHTTPヘッダ等 応答パラメータを操作することを意図しているのに対し、URIと/またはHTTPメソッド、 インターセプタは、エンティティを操作するために意図されている、 エンティティの入力/出力を操作する

ストリームを介して

したがって、gzipエンコーディングはGZipEncoderを登録するだけで簡単にアクティブ化することはできません。フィルタにも登録する必要があります。これが私がFeatureにバンドルされることを期待していた理由です。

重要:ジャージー内に2つのEncodingFilterクラスがあります。 1つはクライアントに属し、もう1つはサーバー実装に属します。彼らは根本的に異なることをするので、間違ったものを使用しないでください。残念なことに、ユニット・テストを実行するときは、クライアント・インターフェースに依存しているため、クラス・パス上に両方とも持っています。

+1

これは非常にひどいです...この解決策は、Jersey 2.0+ – Filipe

+0

の1x(1.6)用のポインタです。 –

関連する問題