日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java gzip rest_RestTemplate与Gzip压缩

發(fā)布時間:2025/3/15 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java gzip rest_RestTemplate与Gzip压缩 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Gzip 是一種壓縮算法,服務器經常通過這個算法來壓縮響應體,再響應給客戶端,從而減少數(shù)據(jù)體積,提高傳輸速度。客戶端再通過Gzip解壓縮,獲取到原始的數(shù)據(jù)。因為需要壓縮計算,所以會耗費額外的CPU資源。

Gzip 與 HttpHeader

對于壓縮,這個行為來說,客戶端與服務器都要經過協(xié)商。只有使用了同一種壓縮算法,才能正確的解碼出數(shù)據(jù)。http協(xié)議中定義了相關的header

Content-Encoding

是一個實體消息首部,用于對特定媒體類型的數(shù)據(jù)進行壓縮。當這個首部出現(xiàn)的時候,它的值表示消息主體進行了何種方式的內容編碼轉換。這個消息首部用來告知客戶端應該怎樣解碼才能獲取在 Content-Type 中標示的媒體類型內容。

一般建議對數(shù)據(jù)盡可能地進行壓縮,因此才有了這個消息首部的出現(xiàn)。不過對于特定類型的文件來說,比如jpeg圖片文件,已經是進行過壓縮的了。有時候再次進行額外的壓縮無助于負載體積的減小,反而有可能會使其增大。

客戶端和服務器都可以使用,表示body中的數(shù)據(jù)采用了什么編碼(壓縮算法)

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Encoding

Accept-Encoding

HTTP 請求頭 Accept-Encoding 會將客戶端能夠理解的內容編碼方式——通常是某種壓縮算法——進行通知(給服務端)。通過內容協(xié)商的方式,服務端會選擇一個客戶端提議的方式,使用并在響應頭 Content-Encoding 中通知客戶端該選擇。

即使客戶端和服務器都支持相同的壓縮算法,在 identity 指令可以被接受的情況下,服務器也可以選擇對響應主體不進行壓縮。導致這種情況出現(xiàn)的兩種常見的情形是:

要發(fā)送的數(shù)據(jù)已經經過壓縮,再次進行壓縮不會導致被傳輸?shù)臄?shù)據(jù)量更小。一些圖像格式的文件會存在這種情況;

服務器超載,無法承受壓縮需求導致的計算開銷。通常,如果服務器使用超過80%的計算能力,微軟建議不要壓縮。

只要 identity —— 表示不需要進行任何編碼——沒有被明確禁止使用(通過 identity;q=0 指令或是 *;q=0 而沒有為 identity 明確指定權重值),則服務器禁止返回表示客戶端錯誤的 406 Not Acceptable 響應。

一般是客戶端使用,表示給服務器說明,客戶端支持的壓縮算法列表。服務從中選擇一個對響應體進行壓縮。

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Accept-Encoding

演示一個手動編/解碼的Demo

服務端手動進行Gzip編碼

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.nio.charset.StandardCharsets;

import java.util.zip.GZIPOutputStream;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.http.HttpHeaders;

import org.springframework.http.MediaType;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

@RequestMapping("/test")

public class TestController {

private static final Logger LOGGER = LoggerFactory.getLogger(TestController.class);

@GetMapping

public void test(HttpServletRequest request, HttpServletResponse reponse) throws IOException {

// 響應體

String content = "昔日齷齪不足夸,今朝放蕩思無涯。春風得意馬蹄疾,一日看盡長安花。";

String acceptEncooding = request.getHeader(HttpHeaders.ACCEPT_ENCODING);

/**

* 獲取客戶端支持的編碼格式,程序可以根據(jù)這個header判斷是否要對響應體進行編碼

*/

LOGGER.info(acceptEncooding);

// 響應體使用 gzip 編碼

reponse.setHeader(HttpHeaders.CONTENT_ENCODING, "gzip");

// 響應體類型是字符串

reponse.setContentType(MediaType.TEXT_PLAIN_VALUE);

// 編碼是utf-8

reponse.setCharacterEncoding(StandardCharsets.UTF_8.displayName());

// Gzip壓縮后響應

reponse.getOutputStream().write(gZip(content.getBytes(StandardCharsets.UTF_8)));

}

/**

* 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();

}

}

}

客戶端手動解碼

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.nio.charset.StandardCharsets;

import java.util.zip.GZIPInputStream;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.http.HttpEntity;

import org.springframework.http.HttpHeaders;

import org.springframework.http.HttpMethod;

import org.springframework.http.MediaType;

import org.springframework.http.ResponseEntity;

import org.springframework.web.client.RestTemplate;

public class Main {

public static final Logger LOGGER = LoggerFactory.getLogger(Main.class);

public static void main(String[] args) throws Exception {

RestTemplate restTemplate = new RestTemplate();

HttpHeaders httpHeaders = new HttpHeaders();

// Accept 表示客戶端支持什么格式的響應體

httpHeaders.set(HttpHeaders.ACCEPT, MediaType.TEXT_PLAIN_VALUE);

// Accept-Encoding 頭,表示客戶端接收gzip格式的壓縮

httpHeaders.set(HttpHeaders.ACCEPT_ENCODING, "gzip");

ResponseEntity responseEntity = restTemplate.exchange("http://localhost/test", HttpMethod.GET, new HttpEntity<>(httpHeaders), byte[].class);

if (!responseEntity.getStatusCode().is2xxSuccessful()) {

// TODO 非200響應

}

// 獲取服務器響應體編碼

String contentEncoding = responseEntity.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING);

if ("gzip".equals(contentEncoding)) { // gzip編碼

// gzip解壓服務器的響應體

byte[] data = unGZip(new ByteArrayInputStream(responseEntity.getBody()));

LOGGER.info(new String(data, StandardCharsets.UTF_8));

} else {

// TODO 其他的編碼

}

}

/**

* 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();

}

}

}

客戶端執(zhí)行日志,準確的解碼了響應體

20:36:54.129 [main] INFO - 昔日齷齪不足夸,今朝放蕩思無涯。春風得意馬蹄疾,一日看盡長安花。

SpringBoot的響應體壓縮配置

實際上,并不需要自己手動去寫這種響應體的壓縮代碼。springboot提供了相關的配置。

SpringBoot2開啟響應壓縮

最后

使用RestTemplate請求文本數(shù)據(jù)接口,發(fā)現(xiàn)解碼后的字符串是亂碼。此時就可以懷疑是不是服務器響應了壓縮后的數(shù)據(jù)。解決這個問題,先嘗試移除Accept-Encoding請求頭,告訴服務器,客戶端不需要壓縮響應體。如果服務器還是響應壓縮后的數(shù)據(jù),嘗試讀取服務器的Content-Encoding頭,根據(jù)服務器的壓縮編碼,自己再進行解壓縮。

原文: https://springboot.io/t/topic/2868

?

總結

以上是生活随笔為你收集整理的java gzip rest_RestTemplate与Gzip压缩的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。