• Spring Boot 与 Gzip 压缩


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

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

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

    常用的压缩算法如下:

    • gzip
    • deflate
    • br

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

    一、使用 Gzip 压缩响应

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

    1. package cn.springdoc.demo.web.controller;
    2. import java.io.IOException;
    3. import java.nio.file.Files;
    4. import java.nio.file.Path;
    5. import java.nio.file.Paths;
    6. import java.util.Optional;
    7. import java.util.zip.GZIPOutputStream;
    8. import org.springframework.http.HttpHeaders;
    9. import org.springframework.http.MediaType;
    10. import org.springframework.web.bind.annotation.GetMapping;
    11. import org.springframework.web.bind.annotation.RequestMapping;
    12. import org.springframework.web.bind.annotation.RestController;
    13. import jakarta.servlet.http.HttpServletRequest;
    14. import jakarta.servlet.http.HttpServletResponse;
    15. @RestController
    16. @RequestMapping("/demo")
    17. public class DemoController {
    18. @GetMapping
    19. public void file (HttpServletRequest request, HttpServletResponse response) throws IOException {
    20. // 20.0 KB 大小的图片文件
    21. Path file = Paths.get("C:\\Users\\KevinBlandy\\Desktop\\springdoc-logo.png");
    22. // 设置文件类型
    23. response.setContentType(Optional.ofNullable(Files.probeContentType(file)).orElse(MediaType.APPLICATION_OCTET_STREAM_VALUE));
    24. // 设置压缩方式为 gzip 【关键点 1:设置正确的 CONTENT_ENCODING 头】
    25. response.setHeader(HttpHeaders.CONTENT_ENCODING, "gzip");
    26. // 包装 response 流为 gzip 流 【关键点 2:使用 GZIPOutputStream 封装 response 流,并写出数据】
    27. try(GZIPOutputStream gzipOutputStream = new GZIPOutputStream(response.getOutputStream())){
    28. // 响应给客户端
    29. Files.copy(file, gzipOutputStream);
    30. }
    31. }
    32. }

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

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

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

    Spring Boot Gzip 压缩响应

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

    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 中添加如下配置:

    1. server:
    2. compression:
    3. # 开启响应压缩
    4. enabled: true
    5. mime-types:
    6. - image/png # 压缩 png 图片
    7. # 进行压缩的最小体积
    8. 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,如下:

    1. @GetMapping
    2. public ResponseEntity<Resource> file (HttpServletRequest request, HttpServletResponse response) throws IOException {
    3. // 20.0 KB 大小的图片文件
    4. Path file = Paths.get("C:\\Users\\KevinBlandy\\Desktop\\springdoc-logo.png");
    5. return ResponseEntity.ok()
    6. .contentType(MediaType.IMAGE_PNG) // 正确设置图片的 Content Type,浏览器才会预览图片
    7. .body(new InputStreamResource(Files.newInputStream(file)));
    8. }

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

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

  • 相关阅读:
    Python 细聊可以媲美 PS 的 PIL 图片处理库
    2022 最新最全 Java 面试八股文(整整 1685 页,14 个技术栈,20 余万字)
    【毕业设计】基于stm32的车牌识别系统 - 物联网 单片机
    git format-patch打补丁
    01.Singleton Pattern 单例模式
    Web架构安全分析/http/URL/Cookie攻击
    Java毕业设计源代码评教评分教务管理系统springboot
    【Linux】tail命令使用
    WebRTC实战-第一章-理论基础
    Vue2路由知识大杂烩, 一下给你全整明白(中)
  • 原文地址:https://blog.csdn.net/leesinbad/article/details/134512632