Nginx 压缩与静态文件优化
Compression and Static File Optimization
概述
压缩和静态文件优化是提升Web性能的关键技术。Nginx提供了强大的压缩功能和静态文件处理能力,能够显著减少带宽使用和提升加载速度。
1. Gzip压缩配置
1.1 基础Gzip配置
http {
# 启用gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml
application/json
application/ld+json;
server {
listen 80;
server_name gzip.example.com;
root /var/www/html;
location / {
try_files $uri $uri/ =404;
}
}
}
1.2 高级Gzip配置
http {
# 详细的gzip配置
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_proxied expired no-cache no-store private auth;
# 排除已压缩文件
gzip_disable "msie6";
# 扩展的MIME类型
gzip_types
text/plain
text/css
text/xml
text/javascript
text/x-component
application/javascript
application/x-javascript
application/json
application/xml
application/rss+xml
application/atom+xml
font/truetype
font/opentype
application/vnd.ms-fontobject
image/svg+xml;
server {
listen 80;
server_name advanced-gzip.example.com;
location / {
# 根据文件大小调整压缩级别
location ~* \.(js|css)$ {
gzip_comp_level 9; # 高压缩比
expires 1y;
}
location ~* \.(html|htm)$ {
gzip_comp_level 6; # 平衡压缩比
expires 1h;
}
try_files $uri $uri/ =404;
}
}
}
2. Brotli压缩
2.1 Brotli配置
# 需要安装nginx-module-brotli模块
load_module modules/ngx_http_brotli_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;
http {
# Brotli压缩配置
brotli on;
brotli_comp_level 6;
brotli_min_length 1024;
brotli_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/json
application/xml
application/rss+xml
application/atom+xml
image/svg+xml;
# 静态Brotli文件
brotli_static on;
server {
listen 80;
server_name brotli.example.com;
root /var/www/html;
location ~* \.(js|css|html)$ {
# 优先使用预压缩的brotli文件
try_files $uri.br $uri =404;
add_header Content-Encoding br;
add_header Vary Accept-Encoding;
}
}
}
2.2 多重压缩策略
http {
# 同时启用gzip和brotli
gzip on;
gzip_comp_level 6;
gzip_types text/plain text/css application/javascript;
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/javascript;
server {
listen 80;
server_name multi-compress.example.com;
location ~* \.(js|css)$ {
# 根据客户端支持选择压缩方式
try_files $uri.br $uri.gz $uri =404;
location ~* \.br$ {
add_header Content-Encoding br;
add_header Content-Type application/javascript;
}
location ~* \.gz$ {
add_header Content-Encoding gzip;
add_header Content-Type application/javascript;
}
}
}
}
3. 静态文件优化
3.1 文件服务优化
server {
listen 80;
server_name static.example.com;
root /var/www/static;
# 开启sendfile
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 文件传输优化
location ~* \.(jpg|jpeg|png|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary Accept-Encoding;
# 优化大文件传输
location ~* \.(pdf|zip|mp4|mp3)$ {
# 启用分片传输
slice 1m;
proxy_cache_key $host$uri$is_args$args$slice_range;
proxy_set_header Range $slice_range;
proxy_cache_valid 200 206 1h;
}
# 关闭访问日志
access_log off;
}
# CSS和JS优化
location ~* \.(css|js)$ {
expires 30d;
add_header Cache-Control "public";
# 启用gzip_static
gzip_static on;
# ETag支持
etag on;
}
}
3.2 图片优化
server {
listen 80;
server_name images.example.com;
root /var/www/images;
# WebP图片支持
location ~* \.(jpg|jpeg|png)$ {
# 检查是否支持WebP
if ($http_accept ~* "webp") {
rewrite ^(.*)$ $1.webp last;
}
expires 1y;
add_header Cache-Control "public, immutable";
}
location ~* \.webp$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary Accept;
# 如果webp文件不存在,回退到原图
try_files $uri @fallback;
}
location @fallback {
rewrite ^(.*)\.webp$ $1 last;
}
# 响应式图片
location /responsive/ {
# 根据屏幕密度提供不同图片
if ($http_user_agent ~* "Mobile") {
rewrite ^/responsive/(.+)$ /mobile/$1 last;
}
if ($arg_dpr = "2") {
rewrite ^/responsive/(.+)$ /2x/$1 last;
}
try_files $uri =404;
}
}
4. 文件合并和最小化
4.1 CSS/JS合并
# 使用concat模块进行文件合并
location /combo {
concat on;
concat_types text/css application/javascript;
concat_unique off;
concat_max_files 30;
concat_delimiter "\n";
# 示例: /combo??style1.css,style2.css,style3.css
root /var/www/assets;
}
# 传统方法:预合并文件
location /assets/ {
# 尝试合并文件,否则回退到单独文件
try_files $uri /combo$uri =404;
expires 1y;
add_header Cache-Control "public, immutable";
gzip_static on;
}
4.2 动态资源优化
# 使用substitute模块进行内容替换
location / {
# 移除HTML中的空白字符
substitute '\s+' ' ' g;
substitute '>\s+<' '><' g;
substitute_filter_types text/html;
proxy_pass http://backend;
}
# 使用Lua进行动态优化
location /optimize {
content_by_lua_block {
local template = ngx.location.capture("/template.html")
if template.status == 200 then
-- 移除注释和多余空白
local content = template.body
content = string.gsub(content, "<!--.--->", "")
content = string.gsub(content, "%s+", " ")
content = string.gsub(content, "> <", "><")
ngx.header.content_type = "text/html"
ngx.say(content)
else
ngx.status = 500
ngx.say("Error loading template")
end
}
}
5. CDN集成优化
5.1 CDN回源优化
# CDN边缘服务器配置
server {
listen 80;
server_name cdn-edge.example.com;
# 设置源站
location / {
proxy_pass http://origin-server.example.com;
# CDN优化头
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-CDN-Pop $server_name;
# 缓存控制
proxy_cache cdn_cache;
proxy_cache_key "$scheme$proxy_host$request_uri";
proxy_cache_valid 200 1h;
proxy_cache_valid 404 1m;
# 添加CDN头
add_header X-Cache-Status $upstream_cache_status;
add_header X-CDN-Pop $server_name;
}
# 静态资源长缓存
location ~* \.(css|js|png|jpg|gif|ico)$ {
proxy_pass http://origin-server.example.com;
proxy_cache cdn_cache;
proxy_cache_valid 200 7d;
expires 30d;
add_header Cache-Control "public, immutable";
}
}
5.2 多CDN负载均衡
upstream cdn_nodes {
server cdn1.example.com weight=3;
server cdn2.example.com weight=2;
server cdn3.example.com weight=1 backup;
}
server {
listen 80;
server_name assets.example.com;
location / {
# 根据文件类型选择CDN节点
if ($request_uri ~* \.(css|js)$) {
proxy_pass http://cdn_nodes;
break;
}
if ($request_uri ~* \.(png|jpg|gif)$) {
proxy_pass http://image_cdn;
break;
}
proxy_pass http://default_cdn;
}
}
6. 性能监控
6.1 压缩效果监控
# 压缩比统计
log_format compression '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'compression_ratio:$gzip_ratio';
server {
access_log /var/log/nginx/compression.log compression;
location / {
gzip on;
gzip_comp_level 6;
proxy_pass http://backend;
}
}
6.2 性能分析脚本
#!/bin/bash
# compression-analyzer.sh
LOG_FILE="/var/log/nginx/access.log"
analyze_compression() {
echo "=== 压缩效果分析 ==="
# 分析不同文件类型的压缩比
echo "文件类型压缩统计:"
tail -10000 $LOG_FILE | \
awk '{
if ($7 ~ /\.css$/) css_count++
if ($7 ~ /\.js$/) js_count++
if ($7 ~ /\.html$/) html_count++
if ($10 != "-") {
if ($7 ~ /\.css$/) css_size += $10
if ($7 ~ /\.js$/) js_size += $10
if ($7 ~ /\.html$/) html_size += $10
}
}
END {
printf "CSS: %d 请求, 平均大小: %.2f KB\n", css_count, css_size/css_count/1024
printf "JS: %d 请求, 平均大小: %.2f KB\n", js_count, js_size/js_count/1024
printf "HTML: %d 请求, 平均大小: %.2f KB\n", html_count, html_size/html_count/1024
}'
}
check_compression_ratio() {
echo "=== 压缩比检查 ==="
# 检查gzip压缩比
curl -H "Accept-Encoding: gzip" -s -w "压缩后大小: %{size_download} bytes\n" \
http://localhost/style.css > /dev/null
curl -s -w "原始大小: %{size_download} bytes\n" \
http://localhost/style.css > /dev/null
}
monitor_static_files() {
echo "=== 静态文件性能监控 ==="
# 统计静态文件请求
static_requests=$(tail -1000 $LOG_FILE | \
grep -E '\.(css|js|png|jpg|gif|ico)' | wc -l)
total_requests=$(tail -1000 $LOG_FILE | wc -l)
static_percentage=$((static_requests * 100 / total_requests))
echo "静态文件请求占比: ${static_percentage}%"
# 分析缓存命中率
cache_hits=$(tail -1000 $LOG_FILE | grep -c "X-Cache-Status: HIT")
cache_rate=$((cache_hits * 100 / total_requests))
echo "缓存命中率: ${cache_rate}%"
}
case "$1" in
"compression") analyze_compression ;;
"ratio") check_compression_ratio ;;
"static") monitor_static_files ;;
"all")
analyze_compression
echo
check_compression_ratio
echo
monitor_static_files
;;
*)
echo "用法: $0 {compression|ratio|static|all}"
;;
esac
7. 自动化优化
7.1 构建时优化
#!/bin/bash
# build-optimizer.sh
ASSETS_DIR="/var/www/assets"
BUILD_DIR="/tmp/build"
# 创建构建目录
mkdir -p $BUILD_DIR
# CSS优化
optimize_css() {
echo "优化CSS文件..."
for css_file in $ASSETS_DIR/*.css; do
filename=$(basename "$css_file")
# 使用cssnano压缩CSS
npx cssnano "$css_file" "$BUILD_DIR/$filename"
# 生成gzip版本
gzip -c "$BUILD_DIR/$filename" > "$BUILD_DIR/${filename}.gz"
# 生成brotli版本
brotli -c "$BUILD_DIR/$filename" > "$BUILD_DIR/${filename}.br"
done
}
# JavaScript优化
optimize_js() {
echo "优化JavaScript文件..."
for js_file in $ASSETS_DIR/*.js; do
filename=$(basename "$js_file")
# 使用terser压缩JS
npx terser "$js_file" -o "$BUILD_DIR/$filename" -c -m
# 生成压缩版本
gzip -c "$BUILD_DIR/$filename" > "$BUILD_DIR/${filename}.gz"
brotli -c "$BUILD_DIR/$filename" > "$BUILD_DIR/${filename}.br"
done
}
# 图片优化
optimize_images() {
echo "优化图片文件..."
for img_file in $ASSETS_DIR/*.{jpg,png}; do
if [ -f "$img_file" ]; then
filename=$(basename "$img_file")
# 使用imagemagick优化
convert "$img_file" -quality 85 -strip "$BUILD_DIR/$filename"
# 生成WebP版本
cwebp -q 85 "$img_file" -o "$BUILD_DIR/${filename%.*}.webp"
fi
done
}
# 执行优化
optimize_css
optimize_js
optimize_images
# 部署优化后的文件
rsync -av $BUILD_DIR/ $ASSETS_DIR/
echo "优化完成!"
7.2 监控和告警
#!/bin/bash
# performance-monitor.sh
THRESHOLD_SIZE=1048576 # 1MB
THRESHOLD_RATIO=50 # 50%压缩比
check_file_sizes() {
large_files=$(find /var/www -name "*.js" -o -name "*.css" -size +${THRESHOLD_SIZE}c)
if [ -n "$large_files" ]; then
echo "警告:发现大文件需要优化:"
echo "$large_files"
return 1
fi
return 0
}
check_compression_config() {
if ! nginx -T | grep -q "gzip on"; then
echo "警告:gzip压缩未启用"
return 1
fi
return 0
}
# 主监控循环
while true; do
if ! check_file_sizes || ! check_compression_config; then
echo "性能检查失败,需要注意!"
# 发送告警邮件
echo "性能告警" | mail -s "Nginx性能告警" admin@example.com
fi
sleep 3600 # 每小时检查一次
done
小结
通过本文学习,你应该掌握:
- Gzip和Brotli压缩配置
- 静态文件优化技巧
- 图片和资源优化方法
- CDN集成和负载均衡
- 性能监控和分析
- 自动化优化流程
下一篇文章将介绍Nginx的连接优化与调优。