OkHttp with GzipRequestInterceptor 导致来自 Jetty 服务器的 400 Bad Request
OkHttp with GzipRequestInterceptor causes 400 Bad Request from Jetty server
我的 Android 应用程序使用 com.squareup.retrofit:retrofit:1.9.0
和 com.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>
您的网络服务器不支持压缩请求。
我的 Android 应用程序使用 com.squareup.retrofit:retrofit:1.9.0
和 com.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>
您的网络服务器不支持压缩请求。