restemplate請求亂碼之content-encoding=“gzip“示例詳解
什么是 RestTemplate
RestTemplate 是從 Spring3.0 開始支持的一個 HTTP 請求工具,它提供了常見的 REST請求方案的模板,例如 GET 請求、POST 請求、PUT 請求、DELETE 請求以及一些通用的請求執(zhí)行方法 exchange 以及 execute。RestTemplate 繼承自 InterceptingHttpAccessor 并且實(shí)現(xiàn)了 RestOperations 接口,其中 RestOptions 接口定義了基本的 RESTful 操作,這些操作在 RestTemplate 中都得到了實(shí)現(xiàn)。
restemplate請求亂碼之content-encoding="gzip"
今天有一個通過Restemplate請求一個天氣API,發(fā)現(xiàn)其Body數(shù)據(jù)是亂碼,同事處理了好久,然并卵,經(jīng)檢查后,發(fā)現(xiàn)頭部信息出了問題。
content-encoding="gzip" content-type="application/json;charset=UTF-8"
返回值是UTF-8,Restemplate設(shè)置的也是UTF-8。在翻看其他博客,發(fā)現(xiàn)問題原因是http存在一個壓縮格式:Gzip。
Gzip是一個壓縮算法,當(dāng)請求數(shù)據(jù)或返回數(shù)據(jù)體積過大,為減少網(wǎng)絡(luò)負(fù)載壓力而使用的壓縮算法。通常在服務(wù)器端使用,客戶端為獲得原始數(shù)據(jù)需通過Gzip解壓。
響應(yīng)頭中的gzip
Content-Encoding
是一個實(shí)體消息首部,用于對特定媒體類型的數(shù)據(jù)進(jìn)行壓縮。當(dāng)這個首部出現(xiàn)的時候,它的值表示消息主體進(jìn)行了何種方式的內(nèi)容編碼轉(zhuǎn)換。這個消息首部用來告知客戶端應(yīng)該怎樣解碼才能獲取在 Content-Type 中標(biāo)示的媒體類型內(nèi)容。
一般建議對數(shù)據(jù)盡可能地進(jìn)行壓縮,因此才有了這個消息首部的出現(xiàn)。
注:客戶端和服務(wù)器都可以使用,表示body中的數(shù)據(jù)采用了什么編碼(壓縮算法)
Accept-Encoding
HTTP 請求頭 Accept-Encoding 會將客戶端能夠理解的內(nèi)容編碼方式——通常是某種壓縮算法——進(jìn)行通知(給服務(wù)端)。通過內(nèi)容協(xié)商的方式,服務(wù)端會選擇一個客戶端提議的方式,使用并在響應(yīng)頭 Content-Encoding 中通知客戶端該選擇。
注:一般是客戶端使用,表示給服務(wù)器說明,客戶端支持的壓縮算法列表。服務(wù)從中選擇一個對響應(yīng)體進(jìn)行壓縮。

/**
* @Title: getClimateByRequst
* @Description: ( 通過request 獲取天氣信息)
* @Author:lijie
* @since 2021/11/9 14:05
* @Version:1.1.0
* @return: climate:封裝的天氣結(jié)果類
*/
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=""http://請求的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ā)送請求
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,請聯(lián)系我,謝謝");
}
}else{
result.setErrored("和風(fēng)API響應(yīng)出錯了");
}
}
}
}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壓縮數(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í)際上,并不需要自己手動去寫這種響應(yīng)體的壓縮代碼。springboot提供了相關(guān)的配置。只針對響應(yīng)壓縮
server:
compression:
# 開啟響應(yīng)壓縮
enabled: true
# 支持的壓縮類型
mime-types:
- application/json
- application/xml
- application/javascript
- text/html
- text/xml
- text/plain
- text/css
- text/javascript
# 默認(rèn)只有響應(yīng)體大于 2028kb 時才會進(jìn)行壓縮
min-response-size: 2048
# 指定不壓縮的user-agent,默認(rèn)為null
# excluded-user-agents對應(yīng)的配置類:org.springframework.boot.context.embedded.Compression
最后
使用RestTemplate請求文本數(shù)據(jù)接口,發(fā)現(xiàn)解碼后的字符串是亂碼。此時除了編碼格式問題外就可以懷疑是不是服務(wù)器響應(yīng)了壓縮后的數(shù)據(jù)。解決這個問題,先嘗試移除Accept-Encoding請求頭,告訴服務(wù)器,客戶端不需要壓縮響應(yīng)體。如果服務(wù)器還是響應(yīng)壓縮后的數(shù)據(jù),嘗試讀取服務(wù)器的Content-Encoding頭,根據(jù)服務(wù)器的壓縮編碼,自己再進(jìn)行解壓縮。
到此這篇關(guān)于restemplate請求亂碼之content-encoding=“gzip“的文章就介紹到這了,更多相關(guān)restemplate請求亂碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot整合Javamail實(shí)現(xiàn)郵件發(fā)送功能
郵件發(fā)送是一個很普遍的功能,springboot整合了相關(guān)的starter,本文給大家介紹了可以實(shí)現(xiàn)一個簡單的郵件發(fā)送功能的實(shí)例,文中通過代碼給大家介紹的非常詳細(xì),感興趣的朋友可以參考下2023-12-12
SpringBoot系列教程JPA之基礎(chǔ)環(huán)境搭建的方法
這篇文章主要介紹了SpringBoot系列教程JPA之基礎(chǔ)環(huán)境搭建的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
JAVA 根據(jù)設(shè)置的概率生成隨機(jī)數(shù)的方法
本篇文章主要介紹了JAVA 根據(jù)設(shè)置的概率生成隨機(jī)數(shù)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-08-08
spring啟動錯誤Singleton bean creation not al
本文主要介紹了spring啟動錯誤Singleton bean creation not allowed while the singletons of this factory are indestruction,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
springboot集成opencv實(shí)現(xiàn)人臉識別功能的詳細(xì)步驟
大家都知道OpenCV是一個基于BSD許可(開源)發(fā)行的跨平臺計算機(jī)視覺和機(jī)器學(xué)習(xí)軟件庫,可以運(yùn)行在Linux、Windows、Android和Mac OS操作系統(tǒng)上今天通過本文給大家分享springboot集成opencv實(shí)現(xiàn)人臉識別,感興趣的朋友一起看看吧2021-06-06
Eclipse開發(fā)JavaWeb項目配置Tomcat的方法步驟
本文主要介紹了Eclipse開發(fā)JavaWeb項目配置Tomcat的方法步驟,首先介紹eclipse開發(fā)JavaWeb項目需要配置的相關(guān)環(huán)境,使用tomcat軟件在本地搭建服務(wù)器,然后再在eclipse環(huán)境下配置tomcat,感興趣的可以了解一下2021-08-08

