12

レトロフィット 1.4.1 と okhttp 1.3.0 を使用して WS で gzip を有効にすると問題が発生します。

RequestInterceptor requestInterceptor = new RequestInterceptor() {
            @Override
            public void intercept(RequestFacade request) {
                request.addHeader("content-type", "application/json");
                request.addHeader("accept-encoding", "gzip");  // Here is the problem
            }
        }; 
RestAdapter restAdapter = new RestAdapter.Builder()
            .setEndpoint(Constants.HOST)
            .setLogLevel(RestAdapter.LogLevel.FULL)
            .setRequestInterceptor(requestInterceptor)
            .build();

次の行にコメントしてrequest.addHeader("accept-encoding", "gzip");も問題はありませんが、gzip が有効になっているとエラーが発生します (私の要求は に分類されfailureます)。

これが私のログキャットですrequest.addHeader("accept-encoding", "gzip");

1326               Retrofit  D  : HTTP/1.1 200 OK
  1326               Retrofit  D  Cache-Control: public, max-age=600
  1326               Retrofit  D  Content-Encoding: gzip
  1326               Retrofit  D  Content-Length: 254
  1326               Retrofit  D  Content-Type: application/json
  1326               Retrofit  D  Date: Wed, 05 Feb 2014 20:22:26 GMT
  1326               Retrofit  D  OkHttp-Received-Millis: 1391631746193
  1326               Retrofit  D  OkHttp-Response-Source: NETWORK 200
  1326               Retrofit  D  OkHttp-Selected-Transport: http/1.1
  1326               Retrofit  D  OkHttp-Sent-Millis: 1391631745971
  1326               Retrofit  D  Server: Apache
  1326               Retrofit  D  Vary: Accept-Encoding
  1326               Retrofit  D  X-Powered-By: PHP/5.3.3-7+squeeze18
  1326               Retrofit  D  ������������}�?O�0��~����nHZOH0 �D�ù���?���~w.�:����=�{�
                               ����|A���=�V/~}o�)���&amp;����<�`�6&��ѳ:��5�ke��V�WD�H�
                               ���ud�J5رyp��G�ːg�y�ʴ����Mxq<�#�Rb`Su�@�0��y��lr;�W�2�C3�
                               T��$���.�
                                          ��xѥ���R
                                                   y���hmt����R����o����v��7@P�
                               4Y����
  1326               Retrofit  D  <--- END HTTP (254-byte body)
  1326             System.err  W  retrofit.RetrofitError: retrofit.converter.ConversionException: com.google.gson.JsonSyntaxException: java.lang.Ille
                               galStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1
  1326             System.err  W  at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:408)
  1326             System.err  W  at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:262)
  1326             System.err  W  at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:313)
  1326             System.err  W  at retrofit.CallbackRunnable.run(CallbackRunnable.java:38)
  1326             System.err  W  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
  1326             System.err  W  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
  1326             System.err  W  at retrofit.Platform$Android$2$1.run(Platform.java:136)
  1326             System.err  W  at java.lang.Thread.run(Thread.java:841)
  1326             System.err  W  Caused by: retrofit.converter.ConversionException: com.google.gson.JsonSyntaxException: java.lang.IllegalStateExcep

gzip を有効にするにはどうすればよいですか?

事前にThx

4

4 に答える 4

28

accept-encodingコードからヘッダーを省略してください。OkHttp は独自のaccept-encodingヘッダーを追加し、サーバーが gzip で応答した場合、OkHttp は黙ってそれを解凍します。

于 2014-02-05T22:13:17.873 に答える
2

同様の問題が発生した後 (私の場合、Accept-Encoding ヘッダーを追加しないと、応答の gzip を解凍できず、Content-Encoding: gzip ヘッダーも残り、JSON パーサーがクラッシュすることがあります)、およびこれを回避する明確な方法はありません。以下の委任されたクライアント実装を作成して、Retrofit の gzip を手動で有効にしました。これは非常にうまく機能しますが、最初にバイト配列にコピーされるため、おそらく非常に大きな (たとえば > 250KB) 応答には使用しないでください。

public class GzippedClient implements Client {

    private Client wrappedClient;

    public GzippedClient(Client wrappedClient) {
        this.wrappedClient = wrappedClient;
    }

    @Override
    public Response execute(Request request) throws IOException {
        Response response = wrappedClient.execute(request);

        boolean gzipped = false;
        for (Header h : response.getHeaders()) {
            if (h.getName() != null && h.getName().toLowerCase().equals("content-encoding") && h.getValue() != null && h.getValue().toLowerCase().equals("gzip")) {
                gzipped = true;
                break;
            }
        }

        Response r = null;
        if (gzipped) {
            InputStream is = null;
            ByteArrayOutputStream bos = null;

            try {
                is = new BufferedInputStream(new GZIPInputStream(response.getBody().in()));
                bos = new ByteArrayOutputStream();

                int b;
                while ((b = is.read()) != -1) {
                    bos.write(b);
                }

                TypedByteArray body = new TypedByteArray(response.getBody().mimeType(), bos.toByteArray());
                r = new Response(response.getUrl(), response.getStatus(), response.getReason(), response.getHeaders(), body);
            } finally {
                if (is != null) {
                    is.close();
                }
                if (bos != null) {
                    bos.close();
                }
            }
        } else {
            r = response;
        }
        return r;
    }

}

RequestInterceptor などを使用して、リクエストに Accept-Encoding ヘッダーを追加する必要もあります。

requestFacade.addHeader("Accept-Encoding", "gzip");

最後に、次のように、既存の Client をこの新しい GzippedClient にラップする必要があります。

restBuilder.setClient(new GzippedClient(new OkClient(okHttpClient)));

それでおしまい。これで、データが gzip されます。

編集: OkHttp バージョン 1.5.1 では、透過的な gzip に関連するバグ ( https://github.com/square/okhttp/pull/632 ) が修正されたようです。私の最初の問題の原因。もしそうなら、gzip の解凍に時折失敗することはもはや発生しないかもしれませんが、これはまだ確認できないほどめったに発生しません。いずれにせよ、透過的なヘッダーの追加/削除と gzip ではなく、独自に依存したい場合は、説明されているソリューションが機能します。

于 2014-03-20T15:29:20.253 に答える
0

グリップをサポートするスクエア製の Okhttp も使用する必要があります。カスタム インスタンスを作成したかどうか、またはデフォルトで有効になっているかどうかがわからない場合は、そのドキュメントを確認する必要があります。

于 2014-02-05T22:14:48.823 に答える