本文主要是介绍restemplate请求乱码之content-encoding=“gzip“,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
restemplate请求乱码之content-encoding="gzip"
- 响应头中的gzip
- Content-Encoding
- Accept-Encoding
- SpringBoot的响应体压缩配置
- 最后
今天有一个通过Restemplate请求一个天气API,发现其Body数据是乱码,同事处理了好久,然并卵,经检查后,发现头部信息出了问题。
content-encoding="gzip"
content-type="application/json;charset=UTF-8"
返回值是UTF-8,Restemplate设置的也是UTF-8。在翻看其他博客,发现问题原因是http存在一个压缩格式:Gzip。
Gzip是一个压缩算法,当请求数据或返回数据体积过大,为减少网络负载压力而使用的压缩算法。通常在服务器端使用,客户端为获得原始数据需通过Gzip解压。
响应头中的gzip
Content-Encoding
是一个实体消息首部,用于对特定媒体类型的数据进行压缩。当这个首部出现的时候,它的值表示消息主体进行了何种方式的内容编码转换。这个消息首部用来告知客户端应该怎样解码才能获取在 Content-Type
中标示的媒体类型内容。
一般建议对数据尽可能地进行压缩,因此才有了这个消息首部的出现。
注:客户端和服务器都可以使用,表示body中的数据采用了什么编码(压缩算法)
Accept-Encoding
HTTP 请求头 Accept-Encoding 会将客户端能够理解的内容编码方式——通常是某种压缩算法——进行通知(给服务端)。通过内容协商的方式,服务端会选择一个客户端提议的方式,使用并在响应头 Content-Encoding
中通知客户端该选择。
注:一般是客户端使用,表示给服务器说明,客户端支持的压缩算法列表。服务从中选择一个对响应体进行压缩。
/*** @Title: getClimateByRequst* @Description: ( 通过request 获取天气信息)* @Author:lijie* @since 2021/11/9 14:05* @Version:1.1.0* @return: climate:封装的天气结果类*/
public Result<Climate> getClimateByRequst(HttpServletRequest request) {Result<Climate> result=new Result<>();try{//通过request请求获得ip地址String ip = WebUtils.getIpByRequset(request);//通过ip获得大致定位Result<Map<String, Object>> locationByIP = this.getLocationByIP(ip);if(locationByIP!=null&&locationByIP.isSuccess()){Map<String, Object> data = locationByIP.getData();String url=""//请求的url地址if(MapUtils.isNotEmpty(data)){String jd = MapUtils.getString(data, "jd");//精度String wd = MapUtils.getString(data, "wd");//纬度HttpHeaders httpHeaders = new HttpHeaders();// Accept 表示客户端支持什么格式的响应体httpHeaders.set("contentType", "application/json;charset=UTF-8");// Accept-Encoding 头,表示客户端可以接收gzip格式的压缩httpHeaders.set(HttpHeaders.ACCEPT_ENCODING, "gzip");//发送请求 ResponseEntity<byte[]> forEntity = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(httpHeaders), byte[].class);if(forEntity.getStatusCode()== HttpStatus.OK){// 获取服务器响应体编码String contentEncoding = forEntity.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING);if ("gzip".equals(contentEncoding)) { // 是gzip编码// gzip解压服务器的Body响应体byte[] weatherData = WebUtils.unGZip(new ByteArrayInputStream(Objects.requireNonNull(forEntity.getBody())));String weatherJson = new String(weatherData, StandardCharsets.UTF_8);Climate climate = JSONObject.parseObject(weatherJson, Climate.class);if(climate!=null){result.setSuccess();result.setData(climate);}} else {// todo 其他的编码result.setErrored("和风API响应值编码不是Gzip,请联系我,谢谢");}}else{result.setErrored("和风API响应出错了");}}}}catch (Exception e){result.setErrored("天气获取出错了");}return result;
}
/*** Gzip解压缩* @param inputStream* @return* @throws IOException*/public static byte[] unGZip(InputStream inputStream) throws IOException {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();try (GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream)) {byte[] buf = new byte[4096];int len = -1;while ((len = gzipInputStream.read(buf, 0, buf.length)) != -1) {byteArrayOutputStream.write(buf, 0, len);}return byteArrayOutputStream.toByteArray();} finally {byteArrayOutputStream.close();}}
/*** Gzip压缩数据* @param data* @return* @throws IOException*/public static byte[] gZip(byte[] data) throws IOException {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream)) {gzipOutputStream.write(data);gzipOutputStream.finish();return byteArrayOutputStream.toByteArray();}}
SpringBoot的响应体压缩配置
实际上,并不需要自己手动去写这种响应体的压缩代码。springboot提供了相关的配置。只针对响应压缩
server:compression:# 开启响应压缩enabled: true# 支持的压缩类型mime-types: - application/json- application/xml- application/javascript- text/html- text/xml- text/plain- text/css- text/javascript# 默认只有响应体大于 2028kb 时才会进行压缩min-response-size: 2048# 指定不压缩的user-agent,默认为null# excluded-user-agents
对应的配置类:org.springframework.boot.context.embedded.Compression
最后
使用RestTemplate
请求文本数据接口,发现解码后的字符串是乱码。此时除了编码格式问题外就可以怀疑是不是服务器响应了压缩后的数据。解决这个问题,先尝试移除Accept-Encoding
请求头,告诉服务器,客户端不需要压缩响应体。如果服务器还是响应压缩后的数据,尝试读取服务器的Content-Encoding
头,根据服务器的压缩编码,自己再进行解压缩。
这篇关于restemplate请求乱码之content-encoding=“gzip“的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!