前些日子了一个新需求,需要在后台使用http通讯。Spring 的RestTemplate的极简风格让我迷恋上了它,虽然项目中没使用过,但是还是大胆的使用了它,因为它出身名门【spring家族】。
1. 第一次遇到乱码
使用RestTemplate代码很简洁,很快就写完了第一个请求。以下使用的是自己对RestTemplate 的封装类。
@RequestMapping(value = "/request",produces="application/json;charset=UTF-8")
public String request(@RequestBody(required = false) String requestBody, @RequestHeader HttpHeaders headers){
String json = null ;
Map<String,Object> map = new HashMap<String,Object>();
try {
String requestURL= headers.getFirst("url");
json=HttpClient.postRest(requestURL,requestBody,headers);
} catch (Exception e) {
logger.error("remote request error ",e);
map.put("code",-1);
map.put("msg","请求失败");
return JSON.toJSONString(map);
}
logger.info("response json : {}",json);
return json;
}
第一次请求就乱码了,乱码如下:
image.png2. 请求恢复正常
后来发现我们使用了自己定义的假域名,本地没有配置hosts,于是我加上了hosts配置,就恢复正常了。
3. 发布线上再次出现乱码
我们在自己测试环境一切都很顺利,很快就可以发布上线了。
最后一个服务发布完毕后开始验证,马上就出现了和第一次乱码一样的问题。
于是我记起来我们在测试环境的时候是因为我们没有配置host的情况,查了线上hosts情况。
又感觉不对劲,线上是域名是真是的域名,应该是不需要配置hosts的。
后面就各种百度,希望有相同的案例。
搜索到的大多数问题是StringHttpMessageConverter 的默认编码为ISO8859-1导致的乱码。只要把StringHttpMessageConverter 配置成UTF-8或在Header中配置contentType为UTF-8即可解决. 我们这么做了然而没有任何效果。
4.使用 Apache HttpComponents 替换了 Spring RestTemplate
这种突发状况暂时没能解决,然而系统一定是要发布的。我们只好把RestTemplate替换成了 Apache 经典的 httpclient组件,然后一切恢复正常。上线成功!
5.RestTemplate 乱码的根本原因
这次发布的乱码问题有同事觉得是RestTemplate的一个bug(我也是这么认为的)。于是我决定找出这个bug。第一个要做的就是复现线上出现的问题。
我在线上机器构建了一个测试的服务,在本地发送请求,果然复现了那个乱码问题。然而同样的代码发布到测试环境却一点问题也没有。
经过排查发现是我们线上Nginx服务配置 gzip压缩,我们测试环境并没有配置。所以我们看到的乱码其实是gzip格式转String之后的样子,大家再看一下。
网上说的乱码其实只是中文乱码。而我们当时疏忽了这一点。
image.png
知道问题就好办啦,我使用JUnit单元测试去掉了header中的gzip。
image.png果然! 所谓的乱码就消失了。
此次乱码的原因太隐蔽,我们把客户端传过来的header直接用来发送给远程服务,忽视了header中的【gzp参数】,刚好测试环境没配置gzip,线上配置了gzip。测试那么顺利,已发布就懵逼了!
网友评论