Feign Gzip 请求错误

Feign 请求 响应的项目报错

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]

还以为是Json使用的对应不上

截取请求的 InputStream 发现 是Gzip的乱码

原来是 Feign 发送的参数较多 自己启用了 Gzip压缩

但是接受时并没有判断 request.Header 里面有没有 Gzip

查了网上其他的回答

https://www.jianshu.com/p/df37eb5f2169

说是 SpringCloud版升级到Hoxton即可

但我的项目本身 SpringCloud 版本一直都是 Hoxton.SR8

还是不行

想了一下觉得 Feign应该只是封装调用请求的方式

毕竟 提供接口给Feign的方法也能被其他http请求调用

那就直接 搜索一下 Springboot gzip解压http 请求

编写Filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* GZIP处理Filter
*/
@WebFilter(filterName = "httpServletGzipFilter", urlPatterns = "/")
public class HttpServletGzipFilter implements Filter {
@Override
public void destroy() {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request), response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {}
}

@Slf4j
class HttpServletRequestWrapper extends javax.servlet.http.HttpServletRequestWrapper {
private HttpServletRequest request;

public HttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}

/**
* 根据 request header 的 Content-Encoding 判断是否启用 gzip 解压数据流
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() throws IOException {
ServletInputStream stream = request.getInputStream();
String contentEncoding = request.getHeader("Content-Encoding");
if (null != contentEncoding && contentEncoding.indexOf("gzip") != -1) {
try {
final GZIPInputStream gzipInputStream = new GZIPInputStream(stream);
ServletInputStream newStream = new ServletInputStream() {
@Override
public int read() throws IOException {
return gzipInputStream.read();
}

@Override
public boolean isFinished() {
return false;
}

@Override
public boolean isReady() {
return false;
}

@Override
public void setReadListener(ReadListener readListener) {}
};
return newStream;
} catch (Exception e) {
log.error("uncompress content fail.", e);
}
}

return stream;
}
}

注册Filter交给Spring管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Configuration
public class HttpServletFilterConfig {
/**
* 注册 HttpServletFilter
*
* @return
*/
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new HttpServletGzipFilter());

List<String> urlPatterns = new ArrayList<>();
urlPatterns.add("/*");
registrationBean.setUrlPatterns(urlPatterns);

return registrationBean;
}
}

接下来按原先的 @RequestBody 即可正常获得数据

1
2
3
4
5
6
7
8
9
@MysdInterior
@PostMapping ("place")
@ApiOperation(value = "生成订单", notes = "提交订单加入数据库")
public PlaceOrderVo place(@RequestBody PlaceOrderVo vo) {
System.out.println(vo);
log.info("mall api 生成订单 : place()");
log.info("参数 :" + String.valueOf(JSONUtil.parse(vo)));
return vo;
}