restemplate請(qǐng)求亂碼之content-encoding=“gzip“示例詳解
什么是 RestTemplate
RestTemplate 是從 Spring3.0 開(kāi)始支持的一個(gè) HTTP 請(qǐng)求工具,它提供了常見(jiàn)的 REST請(qǐng)求方案的模板,例如 GET 請(qǐng)求、POST 請(qǐng)求、PUT 請(qǐng)求、DELETE 請(qǐng)求以及一些通用的請(qǐng)求執(zhí)行方法 exchange 以及 execute。RestTemplate 繼承自 InterceptingHttpAccessor 并且實(shí)現(xiàn)了 RestOperations 接口,其中 RestOptions 接口定義了基本的 RESTful 操作,這些操作在 RestTemplate 中都得到了實(shí)現(xiàn)。
restemplate請(qǐng)求亂碼之content-encoding="gzip"
今天有一個(gè)通過(guò)Restemplate請(qǐng)求一個(gè)天氣API,發(fā)現(xiàn)其Body數(shù)據(jù)是亂碼,同事處理了好久,然并卵,經(jīng)檢查后,發(fā)現(xiàn)頭部信息出了問(wèn)題。
content-encoding="gzip" content-type="application/json;charset=UTF-8"
返回值是UTF-8,Restemplate設(shè)置的也是UTF-8。在翻看其他博客,發(fā)現(xiàn)問(wèn)題原因是http存在一個(gè)壓縮格式:Gzip。
Gzip是一個(gè)壓縮算法,當(dāng)請(qǐng)求數(shù)據(jù)或返回?cái)?shù)據(jù)體積過(guò)大,為減少網(wǎng)絡(luò)負(fù)載壓力而使用的壓縮算法。通常在服務(wù)器端使用,客戶端為獲得原始數(shù)據(jù)需通過(guò)Gzip解壓。
響應(yīng)頭中的gzip
Content-Encoding
是一個(gè)實(shí)體消息首部,用于對(duì)特定媒體類(lèi)型的數(shù)據(jù)進(jìn)行壓縮。當(dāng)這個(gè)首部出現(xiàn)的時(shí)候,它的值表示消息主體進(jìn)行了何種方式的內(nèi)容編碼轉(zhuǎn)換。這個(gè)消息首部用來(lái)告知客戶端應(yīng)該怎樣解碼才能獲取在 Content-Type
中標(biāo)示的媒體類(lèi)型內(nèi)容。
一般建議對(duì)數(shù)據(jù)盡可能地進(jìn)行壓縮,因此才有了這個(gè)消息首部的出現(xiàn)。
注:客戶端和服務(wù)器都可以使用,表示body中的數(shù)據(jù)采用了什么編碼(壓縮算法)
Accept-Encoding
HTTP 請(qǐng)求頭 Accept-Encoding 會(huì)將客戶端能夠理解的內(nèi)容編碼方式——通常是某種壓縮算法——進(jìn)行通知(給服務(wù)端)。通過(guò)內(nèi)容協(xié)商的方式,服務(wù)端會(huì)選擇一個(gè)客戶端提議的方式,使用并在響應(yīng)頭 Content-Encoding
中通知客戶端該選擇。
注:一般是客戶端使用,表示給服務(wù)器說(shuō)明,客戶端支持的壓縮算法列表。服務(wù)從中選擇一個(gè)對(duì)響應(yīng)體進(jìn)行壓縮。
/** * @Title: getClimateByRequst * @Description: ( 通過(guò)request 獲取天氣信息) * @Author:lijie * @since 2021/11/9 14:05 * @Version:1.1.0 * @return: climate:封裝的天氣結(jié)果類(lèi) */ public Result<Climate> getClimateByRequst(HttpServletRequest request) { Result<Climate> result=new Result<>(); try{ //通過(guò)request請(qǐng)求獲得ip地址 String ip = WebUtils.getIpByRequset(request); //通過(guò)ip獲得大致定位 Result<Map<String, Object>> locationByIP = this.getLocationByIP(ip); if(locationByIP!=null&&locationByIP.isSuccess()){ Map<String, Object> data = locationByIP.getData(); String url=""http://請(qǐng)求的url地址 if(MapUtils.isNotEmpty(data)){ String jd = MapUtils.getString(data, "jd");//精度 String wd = MapUtils.getString(data, "wd");//緯度 HttpHeaders httpHeaders = new HttpHeaders(); // Accept 表示客戶端支持什么格式的響應(yīng)體 httpHeaders.set("contentType", "application/json;charset=UTF-8"); // Accept-Encoding 頭,表示客戶端可以接收gzip格式的壓縮 httpHeaders.set(HttpHeaders.ACCEPT_ENCODING, "gzip"); //發(fā)送請(qǐng)求 ResponseEntity<byte[]> forEntity = restTemplate.exchange (url, HttpMethod.GET, new HttpEntity<>(httpHeaders), byte[].class); if(forEntity.getStatusCode()== HttpStatus.OK){ // 獲取服務(wù)器響應(yīng)體編碼 String contentEncoding = forEntity.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING); if ("gzip".equals(contentEncoding)) { // 是gzip編碼 // gzip解壓服務(wù)器的Body響應(yīng)體 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("和風(fēng)API響應(yīng)值編碼不是Gzip,請(qǐng)聯(lián)系我,謝謝"); } }else{ result.setErrored("和風(fēng)API響應(yīng)出錯(cuò)了"); } } } }catch (Exception e){ result.setErrored("天氣獲取出錯(cuò)了"); } 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壓縮數(shù)據(jù) * @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的響應(yīng)體壓縮配置
實(shí)際上,并不需要自己手動(dòng)去寫(xiě)這種響應(yīng)體的壓縮代碼。springboot提供了相關(guān)的配置。只針對(duì)響應(yīng)壓縮
server: compression: # 開(kāi)啟響應(yīng)壓縮 enabled: true # 支持的壓縮類(lèi)型 mime-types: - application/json - application/xml - application/javascript - text/html - text/xml - text/plain - text/css - text/javascript # 默認(rèn)只有響應(yīng)體大于 2028kb 時(shí)才會(huì)進(jìn)行壓縮 min-response-size: 2048 # 指定不壓縮的user-agent,默認(rèn)為null # excluded-user-agents
對(duì)應(yīng)的配置類(lèi):org.springframework.boot.context.embedded.Compression
最后
使用RestTemplate
請(qǐng)求文本數(shù)據(jù)接口,發(fā)現(xiàn)解碼后的字符串是亂碼。此時(shí)除了編碼格式問(wèn)題外就可以懷疑是不是服務(wù)器響應(yīng)了壓縮后的數(shù)據(jù)。解決這個(gè)問(wèn)題,先嘗試移除Accept-Encoding
請(qǐng)求頭,告訴服務(wù)器,客戶端不需要壓縮響應(yīng)體。如果服務(wù)器還是響應(yīng)壓縮后的數(shù)據(jù),嘗試讀取服務(wù)器的Content-Encoding
頭,根據(jù)服務(wù)器的壓縮編碼,自己再進(jìn)行解壓縮。
到此這篇關(guān)于restemplate請(qǐng)求亂碼之content-encoding=“gzip“的文章就介紹到這了,更多相關(guān)restemplate請(qǐng)求亂碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot整合Javamail實(shí)現(xiàn)郵件發(fā)送功能
郵件發(fā)送是一個(gè)很普遍的功能,springboot整合了相關(guān)的starter,本文給大家介紹了可以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的郵件發(fā)送功能的實(shí)例,文中通過(guò)代碼給大家介紹的非常詳細(xì),感興趣的朋友可以參考下2023-12-12SpringBoot系列教程JPA之基礎(chǔ)環(huán)境搭建的方法
這篇文章主要介紹了SpringBoot系列教程JPA之基礎(chǔ)環(huán)境搭建的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06Feign+mybatisplus搭建項(xiàng)目遇到的坑及解決
這篇文章主要介紹了Feign+mybatisplus搭建項(xiàng)目遇到的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03JAVA 根據(jù)設(shè)置的概率生成隨機(jī)數(shù)的方法
本篇文章主要介紹了JAVA 根據(jù)設(shè)置的概率生成隨機(jī)數(shù)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08spring啟動(dòng)錯(cuò)誤Singleton bean creation not al
本文主要介紹了spring啟動(dòng)錯(cuò)誤Singleton bean creation not allowed while the singletons of this factory are indestruction,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07springboot集成opencv實(shí)現(xiàn)人臉識(shí)別功能的詳細(xì)步驟
大家都知道OpenCV是一個(gè)基于BSD許可(開(kāi)源)發(fā)行的跨平臺(tái)計(jì)算機(jī)視覺(jué)和機(jī)器學(xué)習(xí)軟件庫(kù),可以運(yùn)行在Linux、Windows、Android和Mac OS操作系統(tǒng)上今天通過(guò)本文給大家分享springboot集成opencv實(shí)現(xiàn)人臉識(shí)別,感興趣的朋友一起看看吧2021-06-06Eclipse開(kāi)發(fā)JavaWeb項(xiàng)目配置Tomcat的方法步驟
本文主要介紹了Eclipse開(kāi)發(fā)JavaWeb項(xiàng)目配置Tomcat的方法步驟,首先介紹eclipse開(kāi)發(fā)JavaWeb項(xiàng)目需要配置的相關(guān)環(huán)境,使用tomcat軟件在本地搭建服務(wù)器,然后再在eclipse環(huán)境下配置tomcat,感興趣的可以了解一下2021-08-08