RestTemplate请求头accept-encoding导致乱码

背景

生产环境有个服务不能直接在办公电脑所在的网络访问,于是做了一个代理服务,使用RestTemplate做个转发,之前一直没有问题,但是最近几天在请求一个接口时,返回数据竟然乱码了,一下把我搞蒙了,我TM返回值没有中文啊

返回乱码.jpg

而且就是简单的转发,一行代码啊

ResponseEntity<String> responseEntity =
                restTemplate.exchange(url, method, new HttpEntity<Object>(data, headers),
                        new ParameterizedTypeReference<String>() {});

返回值类型都是用String,于是决定定位下原因

定位过程

  1. 首先怀疑是Springboot中类型转换器的编码问题,于是Debug进去看,果然,默认编码是ISO-8859-1

    StringMessageConverter默认编码.jpg

    以为问题解决了,但是往下Debug的时候发现,最终将Response的InputStream转成String的编码是UTF-8,是从响应头里面Content-Type来确定的,这条路堵死

  2. 因为我是将请求数据、请求头原样转发,猜测可能是请求头的原因,于是看传进来的请求头一个一个,控制变量去测,发现把accept-encoding请求头去掉,就不乱码了

    关于accept-encoding请求头,就是客户端告诉服务器,我支持这些压缩算法,你自己选一个来压缩返回,服务器通过响应头content-encoding告诉客户端使用的是那种压缩算法返回数据的。

    Debug的时候打印请求头和响应头,accept-encoding的值是gzip, deflate,content-encoding的值是gzip

原因

到这里乱码的原因就找到了,客户端发送请求的时候带了accept-encoding,告诉服务器是可以使用gzip压缩返回的,但是RestTemplate默认(代码中是直接new RestTemplate())是不支持gzip的,所以将返回数据转成String的时候乱码,即使是字母和数字。

验证

首先打开PostMan的控制台,查看请求的请求头

Postman请求默认带accept-encoding.jpg

倒数第二个就是默认带的accept-encoding

往下Debug,在处理返回数据的时候,手动用Gzip解码一下,看下是否还会乱码,之前StreamUtils.copyToString方法使用UTF-8处理出来是乱码的,现在通过将InputStream通过GZip解码,看下是否正常,Gzip的解码代码如下

public static String unGzip(InputStream inputStream) throws IOException {
    try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
         GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream)) {
        byte[] bytes = new byte[4096];
        int len;
        while ((len = gzipInputStream.read(bytes, 0, bytes.length)) != -1) {
            byteArrayOutputStream.write(bytes, 0, len);
        }
        return new String(byteArrayOutputStream.toByteArray());
    }
}

unzip.jpg

使用unZip解码发现返回值正常了

解决方案

  1. 手动去掉accept-encoding,在代码中直接remove掉请求头

  2. 配置RestTemplate,支持Gzip

    new RestTemplate(new HttpComponentsClientHttpRequestFactory((HttpClientBuilder.create().build())))
    

插曲

在我配置RestTemplate支持Gzip后,还报了另外一个错:“500 Internal Server Error [no body]”经过定位,还是PostMan的问题,Postman请求的时候因为我请求的是本地,postman自动在请求的header中带了host,值为localhost:8080,直接请求后台服务是会报500的,如下图

500_no_body_exception.jpg

直接把host请求头去除即可,重新请求,乱码问题解决。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AE86Jag

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值