restemplate請求亂碼之content-encoding=“gzip“示例詳解
什么是 RestTemplate
RestTemplate 是從 Spring3.0 開始支持的一個 HTTP 請求工具,它提供了常見的 REST請求方案的模板,例如 GET 請求、POST 請求、PUT 請求、DELETE 請求以及一些通用的請求執(zhí)行方法 exchange 以及 execute。RestTemplate 繼承自 InterceptingHttpAccessor 并且實現(xiàn)了 RestOperations 接口,其中 RestOptions 接口定義了基本的 RESTful 操作,這些操作在 RestTemplate 中都得到了實現(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設置的也是UTF-8。在翻看其他博客,發(fā)現(xiàn)問題原因是http存在一個壓縮格式:Gzip。
Gzip是一個壓縮算法,當請求數(shù)據(jù)或返回數(shù)據(jù)體積過大,為減少網(wǎng)絡負載壓力而使用的壓縮算法。通常在服務器端使用,客戶端為獲得原始數(shù)據(jù)需通過Gzip解壓。
響應頭中的gzip
Content-Encoding
是一個實體消息首部,用于對特定媒體類型的數(shù)據(jù)進行壓縮。當這個首部出現(xiàn)的時候,它的值表示消息主體進行了何種方式的內(nèi)容編碼轉換。這個消息首部用來告知客戶端應該怎樣解碼才能獲取在 Content-Type 中標示的媒體類型內(nèi)容。
一般建議對數(shù)據(jù)盡可能地進行壓縮,因此才有了這個消息首部的出現(xiàn)。
注:客戶端和服務器都可以使用,表示body中的數(shù)據(jù)采用了什么編碼(壓縮算法)
Accept-Encoding
HTTP 請求頭 Accept-Encoding 會將客戶端能夠理解的內(nèi)容編碼方式——通常是某種壓縮算法——進行通知(給服務端)。通過內(nèi)容協(xié)商的方式,服務端會選擇一個客戶端提議的方式,使用并在響應頭 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=""http://請求的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");
//發(fā)送請求
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,請聯(lián)系我,謝謝");
}
}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壓縮數(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的響應體壓縮配置
實際上,并不需要自己手動去寫這種響應體的壓縮代碼。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請求文本數(shù)據(jù)接口,發(fā)現(xiàn)解碼后的字符串是亂碼。此時除了編碼格式問題外就可以懷疑是不是服務器響應了壓縮后的數(shù)據(jù)。解決這個問題,先嘗試移除Accept-Encoding請求頭,告訴服務器,客戶端不需要壓縮響應體。如果服務器還是響應壓縮后的數(shù)據(jù),嘗試讀取服務器的Content-Encoding頭,根據(jù)服務器的壓縮編碼,自己再進行解壓縮。
到此這篇關于restemplate請求亂碼之content-encoding=“gzip“的文章就介紹到這了,更多相關restemplate請求亂碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot整合Javamail實現(xiàn)郵件發(fā)送功能
郵件發(fā)送是一個很普遍的功能,springboot整合了相關的starter,本文給大家介紹了可以實現(xiàn)一個簡單的郵件發(fā)送功能的實例,文中通過代碼給大家介紹的非常詳細,感興趣的朋友可以參考下2023-12-12
SpringBoot系列教程JPA之基礎環(huán)境搭建的方法
這篇文章主要介紹了SpringBoot系列教程JPA之基礎環(huán)境搭建的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-06-06
spring啟動錯誤Singleton bean creation not al
本文主要介紹了spring啟動錯誤Singleton bean creation not allowed while the singletons of this factory are indestruction,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-07-07
springboot集成opencv實現(xiàn)人臉識別功能的詳細步驟
大家都知道OpenCV是一個基于BSD許可(開源)發(fā)行的跨平臺計算機視覺和機器學習軟件庫,可以運行在Linux、Windows、Android和Mac OS操作系統(tǒng)上今天通過本文給大家分享springboot集成opencv實現(xiàn)人臉識別,感興趣的朋友一起看看吧2021-06-06
Eclipse開發(fā)JavaWeb項目配置Tomcat的方法步驟
本文主要介紹了Eclipse開發(fā)JavaWeb項目配置Tomcat的方法步驟,首先介紹eclipse開發(fā)JavaWeb項目需要配置的相關環(huán)境,使用tomcat軟件在本地搭建服務器,然后再在eclipse環(huán)境下配置tomcat,感興趣的可以了解一下2021-08-08

