Spring Boot 与 Gzip 压缩

响应压缩是 Web 应用一种常见的优化手段,通过压缩算法减小传输数据的体积,提高传输效率、节约带宽。客户端接收到数据后,使用相同的算法对数据进行解压从而获取到原始数据。

客户端和服务器需要通过 Header 来协商双方支持的压缩算法。

  • Accept-Encoding:请求头,告诉服务器客户端支持的压缩算法(多个使用逗号分割)。例如:Accept-Encoding: gzip, deflate
  • Content-Encoding:响应头,告诉客户端当前 Payload 使用的编码方式(压缩算法)。例如:Content-Encoding: gzip

常用的压缩算法如下:

  • gzip
  • deflate
  • br

JDK 提供了对 GZIP 压缩算法的实现:GZIPOutputStreamGZIPInputStream,我们可以用它们来实现 Gzip 压缩和解压缩。

一、使用 Gzip 压缩响应

在 Spring Boot 应用中创建一个 Controller,使用 GZIPOutputStream 把一张图片文件(20 KB)压缩后响应给客户端。

复制代码
package cn.springdoc.demo.web.controller;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.zip.GZIPOutputStream;

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;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;


@RestController
@RequestMapping("/demo")
public class DemoController {

    @GetMapping
    public void file (HttpServletRequest request, HttpServletResponse response) throws IOException {

        // 20.0 KB 大小的图片文件
        Path file = Paths.get("C:\\Users\\KevinBlandy\\Desktop\\springdoc-logo.png");
        
        // 设置文件类型
        response.setContentType(Optional.ofNullable(Files.probeContentType(file)).orElse(MediaType.APPLICATION_OCTET_STREAM_VALUE));
        
        // 设置压缩方式为 gzip 【关键点 1:设置正确的 CONTENT_ENCODING 头】
        response.setHeader(HttpHeaders.CONTENT_ENCODING, "gzip");
        
        // 包装 response 流为 gzip 流 【关键点 2:使用 GZIPOutputStream 封装 response 流,并写出数据】
        try(GZIPOutputStream gzipOutputStream = new GZIPOutputStream(response.getOutputStream())){
            // 响应给客户端
            Files.copy(file, gzipOutputStream);
        }
    }
}

如上。关键点在于设置 CONTENT_ENCODING Header 为 gzip,告诉浏览器使用了 gzip 压缩算法,浏览器会自动使用相同算法进行解压缩。

最后,使用 GZIPOutputStream 封装 response 流,往 gzipOutputStream 中写入的数据就会被 gzip 压缩。

启动应用,使用浏览器访问:http://localhost:8080/demo

通过控制台的网络面板,你可以看到:

  1. 浏览器通过 Accept-Encoding 告诉服务器,它支持 gzip 压缩算法。
  2. 服务器正确地指定了 Payload 的编码类型为 gzip
  3. 由于使用了 Gzip 压缩,数据的传输体积小于文件体积。

图片在浏览器中预览成功,也说明服务器和客户端都进行了正确的编解码。

二、Spring Boot 配置响应压缩

对于这种如此常用的功能,Spring Boot 早已提供了开箱即用的支持。

可以在 application.yaml / application.properties 文件中配置如下属性,开启全局 Gzip 响应压缩:

|-----------------------------------------|-----------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|
| 属性 | 说明 | 默认值 |
| server.compression.enabled | 是否开启全局响应压缩 | false |
| server.compression.excluded-user-agents | 以逗号分隔的 User Agent 列表,对这些 User Agent 的响应不会被压缩。 | |
| server.compression.mime-types | 逗号分割的文件 MIME Type(媒体类型),这些类型的文件才会被压缩。 | [text/html, text/xml, text/plain, text/css, text/javascript, application/javascript, application/json, application/xml] |
| server.compression.min-response-size | 进行压缩的最低 Content-Length 值。 | 2KB |

application.yaml 中添加如下配置:

复制代码
server:
  compression:
    # 开启响应压缩
    enabled: true
    mime-types: 
      - image/png # 压缩 png 图片
    # 进行压缩的最小体积
    min-response-size: 1KB

其实只需要设置 server.compression.enabled=true 即可,这里故意设置 server.compression.min-response-size=1KB 完全是为了进行演示,因为示例图片不足 2KB

server.compression.min-response-size 值不应该过小,否则压缩后的数据体积可能比原始数据还大。

还需要覆盖 server.compression.mime-types 配置,因为默认配置的压缩的文件类型列表中不包含图片。

修改 Controller,如下:

复制代码
@GetMapping
public ResponseEntity<Resource> file (HttpServletRequest request, HttpServletResponse response) throws IOException {

    // 20.0 KB 大小的图片文件
    Path file = Paths.get("C:\\Users\\KevinBlandy\\Desktop\\springdoc-logo.png");
    
    return ResponseEntity.ok()
            .contentType(MediaType.IMAGE_PNG) // 正确设置图片的 Content Type,浏览器才会预览图片
            .body(new InputStreamResource(Files.newInputStream(file)));
}

这次不自己使用 GZIPOutputStream 进行压缩响应,而是直接返回 ResponseEntity<Resource> 对象。这也是关键点,如果你想基于配置的全局 Gzip 响应压缩生效,则不能自己使用 HttpServletResponse 进行数据响应 ,必须要通过返回对象,由 DispatcherServlet 处理,全局响应压缩才会生效。

重启应用,用浏览器再次请求 http://localhost:8080/demo,你会发现结果跟上节中的测试结果一样。全局 Gzip 压缩配置生效。

相关推荐
天行健的回响几秒前
枚举在实际开发中的使用小Tips
后端
on the way 1233 分钟前
行为型设计模式之Mediator(中介者)
java·设计模式·中介者模式
保持学习ing5 分钟前
Spring注解开发
java·深度学习·spring·框架
wuhunyu6 分钟前
基于 langchain4j 的简易 RAG
后端
techzhi6 分钟前
SeaweedFS S3 Spring Boot Starter
java·spring boot·后端
酷爱码10 分钟前
Spring Boot 整合 Apache Flink 的详细过程
spring boot·flink·apache
异常君30 分钟前
Spring 中的 FactoryBean 与 BeanFactory:核心概念深度解析
java·spring·面试
weixin_4612594144 分钟前
[C]C语言日志系统宏技巧解析
java·服务器·c语言
cacyiol_Z1 小时前
在SpringBoot中使用AWS SDK实现邮箱验证码服务
java·spring boot·spring
竹言笙熙1 小时前
Polarctf2025夏季赛 web java ez_check
java·学习·web安全