OkHttp with GzipRequestInterceptor 导致来自 Jetty 服务器的 400 Bad Request

OkHttp with GzipRequestInterceptor causes 400 Bad Request from Jetty server

我的 Android 应用程序使用 com.squareup.retrofit:retrofit:1.9.0com.squareup.okhttp:okhttp:2.4.0 作为客户端。

更新 服务器 Jetty 9.3.0.v20150612 运行 Java 1.8.0_45-b1。我用另一个应用程序测试了同一台服务器,成功发送了一个压缩请求。

API 有一个带有 @Body Map<String, Object> payload 的命令,自动转换为 JSON。 未压缩时发送效果很好,但它是 92k JSON 正文,因此最好压缩。

我已按照说明 here and created a GzipRequestInterceptor, fixed the content length adding a buffer as instructed here 将其安装到 RestAdapter -

OkHttpClient client = new OkHttpClient();
client.networkInterceptors().add(new GzipRequestInterceptor());

// Create a very simple REST adapter which points the GitAPI endpoint.
RestAdapter restAdapter = new RestAdapter.Builder()
        .setEndpoint(BuildConfig.MBE_SERVER_HOST)
        .setClient(new OkClient(client))
        .build();

出于某种原因,它现在会抛出 Bad Request 错误 -

retrofit.RetrofitError: 400 Bad Request
        at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:388)
        at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240)
        at java.lang.reflect.Proxy.invoke(Proxy.java:397)
        at $Proxy1.report(Unknown Source)
        at mypackage.ReportRequest.loadDataFromNetwork(ReportRequest.java:40)
        at mypackage.Request.doInBackground(Request.java:36)
        at mypackage.Request.doInBackground(Request.java:32)
        at android.os.AsyncTask.call(AsyncTask.java:288)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:231)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
        at java.lang.Thread.run(Thread.java:818)

这里是拦截器-

public class GzipRequestInterceptor implements Interceptor {

    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {
        Request originalRequest = chain.request();
        if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) {
            return chain.proceed(originalRequest);
        }

        Request compressedRequest = originalRequest.newBuilder()
                .header("Content-Encoding", "gzip")
                .method(originalRequest.method(), requestBodyWithContentLength(gzip(originalRequest.body())))
                .build();
        return chain.proceed(compressedRequest);
    }

    private RequestBody gzip(final RequestBody body) {
        return new RequestBody() {
            @Override
            public MediaType contentType() {
                return body.contentType();
            }

            @Override
            public long contentLength() {
                return -1; // We don't know the compressed length in advance!
            }

            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
                body.writeTo(gzipSink);
                gzipSink.close();
            }
        };
    }

    private RequestBody requestBodyWithContentLength(final RequestBody body) throws IOException {

        final Buffer buffer = new Buffer();
        body.writeTo(buffer);

        return new RequestBody() {
            @Override
            public MediaType contentType() {
                return body.contentType();
            }

            @Override
            public long contentLength() {
                return buffer.size();
            }

            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                ByteString snapshot = buffer.snapshot();
                sink.write(snapshot);
            }
        };
    }
}

怎么了?

更新 - 服务器配置

不确定它有多相关,因为它启用了响应压缩,这里是 web.xml 启用了 GzipFilter -

<filter>
    <filter-name>GzipFilter</filter-name>
    <filter-class>org.eclipse.jetty.servlets.GzipFilter</filter-class>
    <init-param>
        <param-name>mimeTypes</param-name>
        <param-value>text/html,text/plain,text/xml,application/xhtml+xml,text/css,application/javascript,image/svg+xml,application/json</param-value>
    </init-param>
    <init-param>
        <param-name>minGzipSize</param-name>
        <param-value>500</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>GzipFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

etc/jetty-gzip.xml -

<Configure id="Server" class="org.eclipse.jetty.server.Server">
  <Get id="next" name="handler" />
  <Set name="handler">
    <New id="GzipHandler" class="org.eclipse.jetty.server.handler.gzip.GzipHandler">
      <Set name="handler"><Ref refid="next" /></Set>
      <Set name="minGzipSize"><Property name="jetty.gzip.minGzipSize" deprecated="gzip.minGzipSize" default="2048"/></Set>
      <Set name="checkGzExists"><Property name="jetty.gzip.checkGzExists" deprecated="gzip.checkGzExists" default="false"/></Set>
      <Set name="compressionLevel"><Property name="jetty.gzip.compressionLevel" deprecated="gzip.compressionLevel" default="-1"/></Set>
      <Set name="excludedAgentPatterns">
        <Array type="String">
          <Item><Property name="jetty.gzip.excludedUserAgent" deprecated="gzip.excludedUserAgent" default=".*MSIE.6\.0.*"/></Item>
        </Array>
      </Set>

      <Set name="includedMethods">
        <Array type="String">
          <Item>GET</Item>
          <Item>POST</Item>
        </Array>
      </Set>

    </New>
  </Set>
</Configure>

您的网络服务器不支持压缩请求。