第 11 章:内容压缩
第 11 章:内容压缩
内容压缩是提升 Web 性能最简单有效的方法之一。合理配置压缩可以减少 60-90% 的传输数据量。
11.1 压缩概述
为什么需要压缩
| 指标 | 未压缩 | gzip 压缩 | 提升 |
|---|
| HTML 页面 | 100 KB | 25 KB | 75% |
| CSS 文件 | 80 KB | 18 KB | 77% |
| JSON API | 50 KB | 12 KB | 76% |
| JS 文件 | 200 KB | 45 KB | 77% |
压缩流程
客户端 服务器
│ │
│── GET /data ─────────────────────→│
│ Accept-Encoding: gzip, br │
│ │── 压缩响应
│←── 200 OK ────────────────────── │
│ Content-Encoding: gzip │
│ Content-Length: 12000 │
│ │
│── 解压响应 ── │
11.2 Accept-Encoding 与 Content-Encoding
请求头:Accept-Encoding
Accept-Encoding: gzip, deflate, br
Accept-Encoding: gzip, deflate, br, zstd;q=1.0
响应头:Content-Encoding
Content-Encoding: gzip
Content-Encoding: br
Content-Encoding: zstd
11.3 压缩算法对比
| 特性 | gzip | deflate | Brotli (br) | Zstandard (zstd) |
|---|
| 压缩率 | 中 | 中 | 高 | 高 |
| 压缩速度 | 快 | 快 | 慢 | 快 |
| 解压速度 | 快 | 快 | 快 | 快 |
| 浏览器支持 | 所有 | 所有 | 现代浏览器 | Chrome 123+ |
| 典型压缩率 | 70-80% | 70-80% | 75-85% | 75-85% |
| 适用场景 | 通用 | 通用 | 静态资源 | API 响应 |
11.4 gzip 配置
Nginx 配置
# 开启 gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6; # 压缩级别 1-9
gzip_min_length 256; # 最小压缩字节数
gzip_buffers 16 8k;
# 压缩的文件类型
gzip_types
text/plain
text/css
text/javascript
text/xml
application/json
application/javascript
application/xml
application/xml+rss
application/vnd.ms-fontobject
application/x-font-ttf
font/opentype
image/svg+xml;
Node.js 配置
const express = require('express');
const compression = require('compression');
const app = express();
// gzip 中间件
app.use(compression({
level: 6, // 压缩级别 1-9
threshold: 1024, // 最小字节数
filter: (req, res) => {
// 不压缩已压缩的内容
if (req.headers['x-no-compression']) {
return false;
}
// 默认过滤
return compression.filter(req, res);
}
}));
11.5 Brotli 配置
Nginx 配置
# 开启 Brotli(需要 ngx_brotli 模块)
brotli on;
brotli_comp_level 6;
brotli_types
text/plain
text/css
text/javascript
application/json
application/javascript
application/xml
image/svg+xml;
优先级配置
# Brotli 优先,gzip 作为降级方案
gzip on;
gzip_comp_level 5;
gzip_types text/plain text/css application/json application/javascript;
brotli on;
brotli_comp_level 5;
brotli_types text/plain text/css application/json application/javascript;
11.6 Zstandard (zstd)
优势
- 压缩速度比 gzip 快 3-5 倍
- 压缩率接近 Brotli
- 解压速度极快
使用示例
import zstandard as zstd
# 压缩
compressor = zstd.ZstdCompressor(level=3)
data = b"Hello, World! " * 1000
compressed = compressor.compress(data)
print(f"原始: {len(data)} 字节, 压缩后: {len(compressed)} 字节")
# 解压
decompressor = zstd.ZstdDecompressor()
decompressed = decompressor.decompress(compressed)
# 客户端请求
GET /api/data HTTP/1.1
Accept-Encoding: zstd, gzip, br
# 服务器响应
HTTP/1.1 200 OK
Content-Encoding: zstd
Content-Length: 1234
11.7 Transfer-Encoding
Transfer-Encoding 用于分块传输压缩,与 Content-Encoding 不同。
| 特性 | Content-Encoding | Transfer-Encoding |
|---|
| 压缩对象 | 完整资源 | 传输过程 |
| 代理处理 | 通常原样转发 | 逐跳处理 |
| 典型使用 | 静态资源 | 流式响应 |
# Transfer-Encoding: chunked + gzip
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Encoding: gzip
1a\r\n
<compressed chunk data>\r\n
0\r\n
\r\n
11.8 压缩策略最佳实践
静态资源
# 静态资源:高压缩率
brotli on;
brotli_comp_level 11; # 最高压缩率(预压缩)
gzip on;
gzip_comp_level 9;
# 使用预压缩文件
location ~* \.(js|css|svg)$ {
brotli_static on; # 优先使用 .br 文件
gzip_static on; # 降级使用 .gz 文件
}
API 响应
# API:中等压缩率(平衡 CPU 和压缩率)
gzip on;
gzip_comp_level 5;
gzip_types application/json;
不需要压缩的情况
| 情况 | 原因 |
|---|
| 已压缩文件(.jpg, .png, .zip) | 无法进一步压缩 |
| 小文件(< 256 字节) | 压缩收益不大 |
| 实时流 | 压缩增加延迟 |
11.9 业务场景:CDN 压缩配置
# 完整的 CDN 边缘节点压缩配置
server {
listen 443 ssl;
# Brotli(首选)
brotli on;
brotli_comp_level 5;
brotli_static on;
brotli_types
text/plain
text/css
text/javascript
application/json
application/javascript
application/xml
image/svg+xml
font/woff2;
# gzip(降级方案)
gzip on;
gzip_comp_level 5;
gzip_vary on;
gzip_proxied any;
gzip_static on;
gzip_min_length 256;
gzip_types
text/plain
text/css
text/javascript
application/json
application/javascript
application/xml
image/svg+xml
font/woff2;
# 静态资源(使用预压缩文件)
location /static/ {
brotli_static on;
gzip_static on;
add_header Cache-Control "public, max-age=31536000, immutable";
}
}
⚠️ 注意事项
- 不要压缩已压缩内容:图片、视频、ZIP 等已压缩格式无需再压缩
- 压缩消耗 CPU:高并发场景需要平衡压缩级别和 CPU 使用
- 使用
gzip_static:预先压缩文件,避免运行时压缩开销 - Vary 头:压缩响应需要
Vary: Accept-Encoding - 安全问题:BREACH 攻击针对压缩+加密的响应,敏感数据考虑不压缩
🔗 扩展阅读
下一章:第 12 章:分块传输与流式响应 — Chunked Transfer、Trailer、SSE