feign启用压缩二三事
项目中启用gzip压缩
compression.request.enabled=true
compression.request.enabled=true
compression.request.mime-types=text/xml,application/xml,application/json
compression.request.min-request-size=2048
compression.response.enabled=true
compression.response.useGzipDecoder=true。
请求时报错
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens; nested exception is com.fasterxml.jackson.core.JsonParseException: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens
at [Source: (PushbackInputStream); line: 1, column: 2]
问题分析
spring-cloud-starter-openfeign版本 2.2.4.release
由于 spring-cloud-starter-openfeign 是pom 真实的处理是在 spring-cloud-open-feign-core中
compression.request 在META-INF中的 spring-configuration-metadata.json定义如下
{
"name": "feign.compression.request",
"type": "org.springframework.cloud.openfeign.encoding.FeignClientEncodingProperties",
"sourceType": "org.springframework.cloud.openfeign.encoding.FeignClientEncodingProperties"
}
找到 FeignClientEncodingProperties
能看到 有个参数定义为
private int minRequestSize = 2048;
继续找到使用的地方
org.springframework.cloud.openfeign.encoding.FeignContentGzipEncodingInterceptor
private boolean requiresCompression(RequestTemplate template) {
final Map<String, Collection<String>> headers = template.headers();
return matchesMimeType(headers.get(HttpEncoding.CONTENT_TYPE))
&& contentLengthExceedThreshold(headers.get(HttpEncoding.CONTENT_LENGTH));
}
这个方法就是判断是否启用gzip 比较的字段是 CONTENT_LENGTH 也就是 Content-Length
于是我们可以得到这个结论
compression.request.min-request-size是针对的 HTTP协议 head中的 Content-Length 字段,如果超过长度就启用压缩 单位是B,默认是2KB就启用压缩
再看作用范围
public void apply(RequestTemplate template) {
if (requiresCompression(template)) {
addHeader(template, HttpEncoding.CONTENT_ENCODING_HEADER,
HttpEncoding.GZIP_ENCODING, HttpEncoding.DEFLATE_ENCODING);
}
}
方法说明是 Called for every request. Add data using methods on the supplied RequestTemplate.
只要是 RequestTemplate支持的类型 均可启用压缩
补充
如果启用gzip压缩,对应的controller方法api需要显示的声明header启用 gzip 例如:
@Headers({"acceptEncoding: gzip","contentType: application/json"})
同理 如果response也启用 那么返回的内容也需要前端支持gzip解析才行
所以 需要支持gzip的时候要注意了