restemplate请求乱码之content-encoding=“gzip“示例详解
什么是 RestTemplate
RestTemplate 是从 Spring3.0 开始支持的一个 HTTP 请求工具,它提供了常见的 REST请求方案的模板,例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute。RestTemplate 继承自 InterceptingHttpAccessor 并且实现了 RestOperations 接口,其中 RestOptions 接口定义了基本的 RESTful 操作,这些操作在 RestTemplate 中都得到了实现。
restemplate请求乱码之content-encoding="gzip"
今天有一个通过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“的文章就介绍到这了,更多相关restemplate请求乱码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Springboot2.1.6集成activiti7出现登录验证的实现
这篇文章主要介绍了Springboot2.1.6集成activiti7出现登录验证的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2020-12-12springboot 集成easy-captcha实现图像验证码显示和登录
本文主要介绍了springboot 集成easy-captcha实现图像验证码显示和登录,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2023-04-04关于@Query注解的用法(Spring Data JPA)
这篇文章主要介绍了关于@Query注解的用法(Spring Data JPA),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2022-03-03Java+Freemarker实现根据XML模板文件生成Word文档
这篇文章主要为大家详细介绍了Java如何使用Freemarker实现根据XML模板文件生成Word文档,文中的示例代码讲解详细,感兴趣的小伙伴可以学习一下2023-11-11Spring中@Autowired和@Resource注解相同点和不同点
这篇文章主要介绍了Spring中@Autowired和@Resource注解相同点和不同点,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧2024-01-01Spring Boot配置application.yml及根据application.yml选择启动配置的操作
Spring Boot中可以选择applicant.properties 作为配置文件,也可以通过在application.yml中进行配置,让Spring Boot根据你的选择进行加载启动配置文件,本文给大家介绍Spring Boot配置application.yml及根据application.yml选择启动配置的操作方法,感兴趣的朋友一起看看吧2023-10-10
最新评论