压缩:
在 Spring Boot 中配置 Controller 的请求 / 响应报文压缩,核心是通过 服务器原生配置 或 自定义拦截器 启用 Gzip/Brotli 压缩,减少网络传输量(尤其对 JSON、HTML 等文本类数据效果显著),且无需依赖 HTTP/2 环境,HTTP/1.1 也完全适用。以下是两种主流实现方案,覆盖通用场景和自定义需求:
一、核心前提
- 压缩适用场景:仅对 文本类数据(如 JSON、XML、HTML、CSS)有效,对二进制数据(图片、视频、文件)无效(这类数据本身已压缩,再次压缩收益极低)。
- 请求压缩需客户端配合:客户端需将请求体压缩后发送,并在请求头携带
Content-Encoding: gzip;服务器需配置解压逻辑。 - 响应压缩自动兼容:服务器压缩响应后,会在响应头添加
Content-Encoding: gzip,客户端(浏览器、Postman 等)会自动解压。
二、方案 1:服务器原生配置(推荐,零代码)
Spring Boot 内置的 Tomcat、Jetty、Undertow 服务器均支持通过配置文件启用压缩,无需修改业务代码,适用于全局压缩需求。
1. 通用配置(所有服务器通用)
在 application.yml 中添加以下配置,覆盖响应压缩(核心)和请求压缩(可选):
yaml
server:
# 响应压缩配置(必配,优化接口返回数据)
compression:
enabled: true # 开启响应压缩
mime-types: application/json,application/xml,text/html,text/css,text/plain,application/javascript # 需压缩的响应类型(文本类优先)
min-response-size: 2048 # 最小响应大小(字节):小于此值不压缩(避免小数据压缩开销 > 收益)
# 请求压缩配置(可选,处理客户端压缩的请求体)
compression.request:
enabled: true # 开启请求压缩(服务器自动解压客户端发送的压缩请求)
mime-types: application/json,application/xml # 需解压的请求类型(仅处理文本类请求体)
min-request-size: 1024 # 最小请求大小(字节):小于此值不解压
2. 各服务器特殊配置(精细化控制)
(1)Tomcat 服务器(默认)
若需调整压缩级别(平衡压缩速度和压缩比),可添加 Tomcat 专属配置:
yaml
server:
compression:
enabled: true
# ... 通用配置不变
tomcat:
compression-level: 6 # 压缩级别(1-9):1=最快(压缩比低),9=最佳(压缩比高,速度慢),默认 6
(2)Undertow 服务器(支持 Brotli 压缩,比 Gzip 更优)
Undertow 可启用 Brotli 压缩(压缩率比 Gzip 高 10%-20%),适合对带宽敏感的场景:
yaml
server:
compression:
enabled: true
# ... 通用配置不变
undertow:
compression:
brotli:
enabled: true # 开启 Brotli 压缩(优先级高于 Gzip)
level: 6 # Brotli 压缩级别(1-11),默认 6
(3)Jetty 服务器
Jetty 无需额外配置,通用压缩配置已覆盖核心功能,直接使用即可。
三、方案 2:自定义拦截器(局部压缩,精细化控制)
若需仅对 特定 Controller / 接口 启用压缩(如仅 /api/** 路径,排除文件下载接口),可通过 Spring 拦截器实现,灵活控制压缩范围。
1. 自定义响应压缩拦截器
java
运行
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
/**
* 自定义 Gzip 响应压缩拦截器
*/
public class GzipResponseInterceptor implements HandlerInterceptor {
// 拦截前:包装响应流,后续 Controller 输出的内容会先存入字节流
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
// 1. 判断客户端是否支持压缩(请求头携带 Accept-Encoding: gzip)
String acceptEncoding = request.getHeader("Accept-Encoding");
if (acceptEncoding != null && acceptEncoding.contains("gzip")) {
// 2. 包装响应流为 Gzip 流,替换默认输出流
GzipResponseWrapper gzipWrapper = new GzipResponseWrapper(response);
response.setHeader("Content-Encoding", "gzip"); // 告知客户端响应已压缩
request.setAttribute("gzipWrapper", gzipWrapper); // 存入请求域,后续关闭流
}
return true;
}
// 接口处理完成后:关闭 Gzip 流,确保压缩后的数据写入响应
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws IOException {
GzipResponseWrapper gzipWrapper = (GzipResponseWrapper) request.getAttribute("gzipWrapper");
if (gzipWrapper != null) {
gzipWrapper.finishResponse(); // 输出压缩后的数据
}
}
/**
* 自定义响应包装类:将响应内容写入 Gzip 流
*/
static class GzipResponseWrapper extends javax.servlet.http.HttpServletResponseWrapper {
private final ByteArrayOutputStream byteStream;
private final GZIPOutputStream gzipStream;
public GzipResponseWrapper(HttpServletResponse response) throws IOException {
super(response);
this.byteStream = new ByteArrayOutputStream();
this.gzipStream = new GZIPOutputStream(byteStream);
}
// 重写输出流:所有 Controller 的响应会写入 Gzip 流
@Override
public javax.servlet.ServletOutputStream getOutputStream() throws IOException {
return new javax.servlet.ServletOutputStream() {
@Override
public void write(int b) throws IOException {
gzipStream.write(b);
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setWriteListener(javax.servlet.WriteListener listener) {}
};
}
// 完成响应:将压缩后的数据写入原始响应流
public void finishResponse() throws IOException {
gzipStream.finish(); // 关闭 Gzip 流,确保数据完整
byte[] compressedData = byteStream.toByteArray();
HttpServletResponse originalResponse = getResponse();
originalResponse.setContentLength(compressedData.length); // 设置压缩后的数据长度
originalResponse.getOutputStream().write(compressedData);
originalResponse.getOutputStream().flush();
}
}
}
2. 注册拦截器(指定生效范围)
java
运行
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 仅对 /api/** 路径的接口启用压缩,排除文件下载接口
registry.addInterceptor(new GzipResponseInterceptor())
.addPathPatterns("/api/**") // 生效路径
.excludePathPatterns("/api/file/download"); // 排除无需压缩的路径(如二进制文件)
}
}
四、验证压缩是否生效
1. 响应压缩验证(用 Postman 或浏览器)
- 步骤 1:发送请求时,在请求头添加
Accept-Encoding: gzip(Postman 会自动添加,可在 “Headers” 面板查看)。 - 步骤 2:查看响应头,若包含
Content-Encoding: gzip,且响应体大小比未压缩时显著减小(如 10KB 的 JSON 压缩到 2KB),说明压缩生效。
2. 请求压缩验证(需客户端配合)
- 客户端操作:将请求体(如 JSON)用 Gzip 压缩后发送,请求头添加
Content-Encoding: gzip。 - 服务器验证:在 Controller 中打印请求体内容,若能正常解析(而非乱码),说明服务器解压成功。
五、注意事项
- 避免过度压缩:小数据(如 < 2KB)无需压缩 —— 压缩过程的 CPU 开销可能大于带宽节省的收益,通过
min-response-size/min-request-size控制。 - 排除二进制接口:对文件下载、图片返回等接口,需通过
excludePathPatterns排除压缩(避免二进制数据被二次压缩导致损坏)。 - 压缩级别选择:生产环境推荐使用默认级别(6),平衡速度和压缩比;若服务器 CPU 资源紧张,可降低到 3-4;若带宽紧张,可提高到 7-8(不建议 9,CPU 开销过高)。
总结
- 全局压缩:优先用方案 1(服务器原生配置),零代码、易维护,适合全量接口压缩。
- 局部压缩:用方案 2(自定义拦截器),灵活控制生效范围,适合特定接口需求。
两种方案均兼容 HTTP/1.1,无需依赖 HTTP/2,能有效减少网络传输量,降低带宽成本,提升接口响应速度(尤其跨地域、弱网络场景)。
要不要我帮你整理一份 Spring Boot 报文压缩配置模板?包含全局配置、各服务器特殊配置、自定义拦截器代码,你可以直接复制到项目中使用。
---------------------------------------------------------------------------------------------------
解压:
客户端解压服务器的压缩响应,核心逻辑是根据服务器返回的 Content-Encoding 头,选择对应算法(如 Gzip)解压响应体,不同客户端(浏览器、Postman、自定义代码客户端)的实现方式不同,但大多无需手动处理(工具 / 框架会自动完成)。以下是常见客户端的解压方式详解:
一、核心原理:基于 HTTP 头的 “协商解压”
服务器启用响应压缩后,会在响应头中添加 Content-Encoding: gzip(或 br 表示 Brotli),告知客户端 “响应体已用该算法压缩”。客户端只需:
- 发送请求时在请求头携带
Accept-Encoding: gzip, br(告知服务器 “我支持这些压缩算法”); - 接收响应后,检测
Content-Encoding头,用对应算法解压响应体。
二、常见客户端的解压方式
1. 浏览器(Chrome、Firefox、Edge 等):全自动,无需手动操作
浏览器原生支持 Gzip/Brotli 解压,整个过程完全自动化:
- 发送请求:浏览器会自动在请求头添加
Accept-Encoding: gzip, deflate, br(支持主流压缩算法); - 接收响应:若响应头有
Content-Encoding: gzip,浏览器会自动解压响应体,渲染页面时使用解压后的内容; - 验证方式:打开浏览器开发者工具(F12)→ Network 面板→ 选中任意请求→ Response Headers 中查看
Content-Encoding(有值说明压缩生效),Preview 面板显示的是解压后的正常内容(非乱码)。
2. 接口测试工具(Postman、Apifox):自动解压,可手动关闭
这类工具默认开启自动解压,无需额外配置:
- Postman:
- 发送请求时,工具自动添加
Accept-Encoding: gzip, deflate; - 接收响应后,若响应头有
Content-Encoding,会自动解压,在 Body 面板显示正常内容(非乱码); - 若需关闭自动解压:点击请求设置(右上角齿轮图标)→ 取消勾选 Automatically decode gzip responses。
- 发送请求时,工具自动添加
- Apifox:逻辑与 Postman 一致,默认自动解压,可在 “设置 - 请求设置” 中关闭。
3. 自定义代码客户端(Java、Python、JavaScript 等):需手动处理(或用框架自动处理)
若用代码编写客户端(如后端服务调用其他 API),需根据语言 / 框架特性,手动配置解压逻辑(或依赖框架原生支持)。
(1)Java 客户端(以 OkHttp 为例):框架自动解压
OkHttp 默认支持 Gzip 解压,无需手动写解压代码:
java
运行
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class JavaHttpClient {
public static void main(String[] args) throws Exception {
OkHttpClient client = new OkHttpClient(); // 默认启用 Gzip 解压
Request request = new Request.Builder()
.url("https://your-springboot-api.com/api/data") // 你的 Spring Boot 接口
.build(); // OkHttp 自动添加 Accept-Encoding: gzip
try (Response response = client.newCall(request).execute()) {
// 直接获取解压后的响应体(无需手动处理)
String responseBody = response.body().string();
System.out.println("解压后的响应:" + responseBody);
}
}
}
- 原理:OkHttp 内部会检测响应头的
Content-Encoding,若为gzip,自动用GZIPInputStream解压。
(2)Python 客户端(以 requests 为例):自动解压
requests 库默认开启 Gzip 解压,逻辑与 OkHttp 类似:
python
运行
import requests
# requests 自动添加 Accept-Encoding: gzip, deflate
response = requests.get("https://your-springboot-api.com/api/data")
# 直接获取解压后的内容(response.text 已解压)
print("解压后的响应:", response.text)
# 验证是否启用了压缩:查看响应头
print("压缩算法:", response.headers.get("Content-Encoding")) # 输出 gzip
(3)JavaScript 客户端(浏览器端):自动解压
浏览器端 JS 发送请求时,fetch 或 XMLHttpRequest 会自动处理解压:
javascript
运行
// fetch 示例:自动解压
fetch("https://your-springboot-api.com/api/data")
.then(response => response.json()) // 自动解压后解析为 JSON
.then(data => console.log("解压后的响应:", data));
// XMLHttpRequest 示例:自动解压
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://your-springboot-api.com/api/data");
xhr.onload = function() {
console.log("解压后的响应:", xhr.responseText); // 已自动解压
};
xhr.send();
(4)手动解压示例(Java,不用框架时):
若不用 OkHttp 等框架,需手动用 GZIPInputStream 解压:
java
运行
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.GZIPInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ManualGzipClient {
public static void main(String[] args) throws Exception {
URL url = new URL("https://your-springboot-api.com/api/data");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 1. 告知服务器支持 Gzip 压缩
conn.setRequestProperty("Accept-Encoding", "gzip");
// 2. 接收响应,判断是否需要解压
String contentEncoding = conn.getHeaderField("Content-Encoding");
BufferedReader reader;
if ("gzip".equals(contentEncoding)) {
// 3. 手动用 GZIPInputStream 解压
reader = new BufferedReader(new InputStreamReader(
new GZIPInputStream(conn.getInputStream()), "UTF-8"));
} else {
// 无需解压,直接读取
reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
}
// 4. 读取解压后的内容
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
System.out.println("解压后的响应:" + response.toString());
}
}
三、常见问题:客户端解压失败的原因
- 客户端未发送
Accept-Encoding头:服务器会认为客户端不支持压缩,直接返回未压缩的响应,客户端无需解压(也不会有Content-Encoding头)。 - 响应体不是文本类数据:若服务器误将图片、视频等二进制数据压缩,客户端解压后会出现乱码(需在服务器配置中排除这些 MIME 类型)。
- 压缩算法不匹配:服务器用 Brotli(
Content-Encoding: br)压缩,但客户端仅支持 Gzip,会导致解压失败(需客户端添加Accept-Encoding: br支持)。
总结
客户端解压的核心是 “基于 HTTP 头的自动协商”:
- 浏览器 / 测试工具:完全自动,无需手动操作;
- 代码客户端:主流框架(OkHttp、requests)默认自动解压,仅在不用框架时需手动处理;
- 关键是确保客户端发送
Accept-Encoding头,且支持服务器使用的压缩算法(Gzip 最通用,Brotli 需额外配置)。
只要服务器配置正确,客户端几乎无需额外开发,即可完成解压,实现 “压缩传输 - 自动解压” 的完整流程。
要不要我帮你整理一份 常见客户端解压配置清单?包含浏览器、Postman、Java/Python 代码客户端的具体操作步骤和验证方法,方便你快速核对客户端配置。
1238

被折叠的 条评论
为什么被折叠?



