搞懂HTTP GZIP压缩:请求头配置、服务端开启、适用场景全解析

在接口开发、网络请求优化中,GZIP压缩是提升传输速度、降低流量消耗的核心手段。很多开发者都会配置 Accept-Encoding: gzip, deflate 请求头,但绝大多数人都搞不懂:加了这个头到底会不会压缩数据?请求体和响应体压缩有什么区别?什么场景需要开启GZIP?服务端该如何配置?

本文从零梳理GZIP核心原理、请求/响应压缩区别、主流服务端配置方案、适配场景与避坑指南,看完彻底吃透HTTP压缩优化,告别盲目配置。

一、核心误区:Accept-Encoding 到底有什么用?

先抛出最核心的结论,解决90%开发者的困惑:

1. request.setHeader("Accept-Encoding", "gzip, deflate") 不会压缩客户端请求体(上传数据)

2. 该请求头仅用于协商服务端响应体(下载数据)压缩

3. 即便配置了该请求头,服务端也不一定返回压缩数据,由服务端配置决定

1.1 两个极易混淆的HTTP压缩请求头

HTTP压缩核心靠两个头部,作用对象完全不同,千万别混淆:

请求头

作用对象

核心含义

Accept-Encoding

服务端响应(下行数据)

客户端声明:我支持解压GZIP/DEFLATE压缩数据,询问服务端是否可以压缩返回结果

Content-Encoding

请求体/响应体(双向)

数据标记:当前报文已经被压缩,告知对端需要解压

1.2 客户端真实行为说明

  • 响应压缩(下行):客户端携带 Accept-Encoding,服务端满足条件后压缩响应数据,响应头返回 Content-Encoding: gzipJava原生客户端需手动解压,OkHttp/浏览器自动解压

  • 请求压缩(上行):仅配置 Accept-Encoding 完全无效!想要压缩客户端上传的请求体,必须手动压缩数据 + 主动添加 Content-Encoding: gzip 请求头。

二、服务端如何开启GZIP响应压缩(最全配置)

响应压缩是开发中最常用的优化手段,无需改造业务代码,支持 Nginx、SpringBoot、原生Tomcat 三种主流方案,优先推荐Nginx全局压缩,不占用业务服务CPU。

2.1 Nginx开启GZIP(推荐首选)

Nginx层统一压缩,覆盖静态资源、所有接口响应,性能最优,彻底解耦业务服务。

http {
    # 开启gzip压缩
    gzip on;
    # 触发压缩的最小文件大小,小于1k不压缩(避免小头冗余)
    gzip_min_length 1k;
    # 压缩级别1-9,6为性价比最高(平衡CPU与压缩率)
    gzip_comp_level 6;
    # 需要压缩的资源类型(核心:必须包含application/json适配接口)
    gzip_types
        text/plain
        text/css
        application/json
        application/javascript
        text/xml
        image/svg+xml;
    # 携带Accept-Encoding头才返回压缩数据,兼容所有客户端
    gzip_vary on;
    # 对反向代理的后端服务开启压缩
    gzip_proxied any;
}

生效验证:执行 nginx -s reload,通过curl测试,响应头出现 Content-Encoding: gzip 即配置成功。

2.2 SpringBoot内置GZIP压缩(无Nginx场景)

单机部署、无反向代理时,直接通过yml配置开启,零代码侵入。

server:
  compression:
    enabled: true # 开启响应压缩
    min-response-size: 1024 # 大于1KB的数据才压缩
    mime-types: text/html,text/css,application/json,application/javascript,text/xml # 压缩文件类型

2.3 原生Tomcat开启压缩

传统SSM、原生Tomcat项目,修改 conf/server.xml 的Connector节点:

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           compression="on"
           compressionMinSize="1024"
           compressableMimeType="text/html,text/css,application/json,application/javascript"/>

2.4 特殊场景:接口手动GZIP压缩

极少数特殊接口需要单独压缩,可手动编码实现,不推荐全局使用:

@GetMapping("/data")
public ResponseEntity<byte[]> getData(HttpServletResponse response) throws IOException {
    // 模拟大量返回数据
    String json = "{\"list\":[大量接口数据]}";
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    // GZIP压缩输出流
    try(GZIPOutputStream gzipOut = new GZIPOutputStream(baos)){
        gzipOut.write(json.getBytes(StandardCharsets.UTF_8));
    }
    byte[] gzipBytes = baos.toByteArray();

    // 设置压缩响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Encoding", "gzip");
    headers.add("Content-Type", "application/json;charset=utf-8");
    return new ResponseEntity<>(gzipBytes, headers, HttpStatus.OK);
}

三、客户端请求体压缩实操(极少用)

普通接口无需开启上传压缩,仅大批量数据提交场景使用,完整实操代码:

// 1. 手动压缩请求体数据
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try(GZIPOutputStream gzip = new GZIPOutputStream(bos)){
    gzip.write(jsonStr.getBytes(StandardCharsets.UTF_8));
}
byte[] compressBody = bos.toByteArray();

// 2. 配置双向压缩请求头
request.setHeader("Accept-Encoding", "gzip, deflate");
request.setHeader("Content-Encoding", "gzip"); // 声明请求体已压缩
request.setHeader("Content-Length", String.valueOf(compressBody.length));

// 3. 写入压缩数据并发送
try(OutputStream out = request.getOutputStream()){
    out.write(compressBody);
}

四、精准判断:什么场景需要开启GZIP压缩?

压缩的核心是权衡CPU损耗与网络传输收益,不是所有场景都适合开启,盲目开启会造成性能负优化。

4.1 必须开启压缩的场景

  • 公网/移动端接口:手机4G/5G、弱网环境,JSON列表、报表、批量查询等大数据接口,压缩率可达60%-85%,大幅降低延迟、节省用户流量。

  • 前端静态资源:JS、CSS、HTML文本资源,压缩率极高,是网站性能优化标配。

  • 跨地域/跨机房调用:异地微服务、跨机房数据同步,减少公网传输耗时与带宽成本。

  • 批量数据接口:爬虫对接、批量导入导出、日志查询等一次性返回大量文本数据的接口。

  • 按量计费流量服务:云服务器、对象存储下载场景,压缩可直接降低出网流量账单。

4.2 绝对不要开启压缩的场景

  • 已压缩二进制文件:JPG、PNG、MP4、ZIP等文件本身已完成压缩,再次压缩无效果,只会浪费服务端、客户端CPU资源。

  • 内网本地调用:同机房、本机服务互调,内网带宽极高、延迟极低,压缩解压耗时大于传输耗时,属于负优化。

  • 极小报文接口:仅返回状态码、简单提示语(几十字节),压缩后携带头部信息,体积反而变大,配置 min-response-size:1k 可自动规避。

  • CPU打满的高并发服务:服务本身CPU负载过高,建议交由Nginx处理压缩,避免业务服务CPU瓶颈导致接口超时。

五、常见踩坑总结

  • 不要混淆 Accept-Encoding(协商响应压缩)Content-Encoding(标记报文压缩)

  • Java原生HttpURLConnection、RestTemplate不会自动解压GZIP响应,需手动包装 GZIPInputStream,否则数据乱码。

  • 图片、视频严禁加入压缩MIME列表,无收益且损耗性能。

  • 请求体压缩极少使用,仅大批量上传场景需要,普通接口无需配置。

  • 优先Nginx全局压缩,其次SpringBoot内置压缩,避免业务服务承担压缩计算压力。

六、快速取舍口诀

公网文本大数据,GZIP必开;内网二进制小报文,坚决不开;CPU紧张交给Nginx,小阈值自动兜底。

总结

1. Accept-Encoding 仅协商响应压缩,不处理客户端上传数据;

2. 服务端优先Nginx全局压缩,配置简单、性能最优;

3. 压缩只适配文本大数据,二进制、极小报文、内网调用无需开启;

4. 上行压缩场景极少,仅大批量数据上传需要手动实现。

更多推荐