後端:Tomcat 8080 埠運行 Java Web 應用(動態 JSP/Servlet、靜態圖片/JS/CSS 混合)。
前端:Nginx 80 埠反向代理,實現:
upstream tomcat_backend {
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
keepalive 64; # 連接複用
}
server {
listen 80;
server_name www.example.com;
# 通用代理參數
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-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Connection ""; # 清除 Connection 頭,配合 keepalive
location / {
proxy_pass https://tomcat_backend;
}
}
# 靜態資源域名
server {
listen 80;
server_name static.example.com;
root /var/www/static; # 直接服務本地靜態文件
expires 30d;
add_header Cache-Control "public, immutable";
}
# 動態應用域名
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass https://tomcat_backend;
}
}
# 前端頁面引用:
server {
listen 80;
server_name www.example.com;
# 靜態資源直接服務
location ~* \.(gif|jpg|jpeg|png|bmp|swf|css|js|ico|woff2?|svg)$ {
root /var/www/app; # 需同步 Tomcat 靜態資源到此目錄
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# 動態請求代理
location / {
proxy_pass https://tomcat_backend;
}
}
# Tomcat 部署時將靜態資源放入 /static 目錄
location /static/ {
alias /var/www/app/static/; # 注意 alias 末尾斜槿
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
location / {
proxy_pass https://tomcat_backend;
}
若靜態資源無法同步到 Nginx 本地(如多台 Tomcat、動態生成的圖表),需代理緩存:
# http 上下文
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=tomcat_cache:100m inactive=7d max_size=20g use_temp_path=off;
proxy_temp_path /data/nginx/tmp; # 必須同檔案系統
server {
listen 80;
server_name www.example.com;
# 靜態資源:代理緩存
location ~* \.(gif|jpg|jpeg|png|bmp|swf|css|js|ico|woff2?|svg)$ {
proxy_cache tomcat_cache;
proxy_cache_key "$scheme$request_method$host$request_uri$args";
proxy_cache_valid 200 302 30d;
proxy_cache_valid 404 1m;
proxy_cache_min_uses 1;
proxy_cache_methods GET HEAD;
proxy_pass https://tomcat_backend;
# 繼承通用 proxy_set_header
expires 30d; # 給客戶端瀏覽器緩存頭
}
# 動態請求:不緩存
location / {
proxy_cache off;
proxy_pass https://tomcat_backend;
}
# 手動清除緩存
location ~ /purge(/.*) {
allow 10.0.0.0/8;
allow 127.0.0.1;
deny all;
proxy_cache_purge tomcat_cache "$scheme$request_method$host$1$is_args$args";
}
}
# 下載模組
git clone https://github.com/FRiCKLE/ngx_cache_purge.git /usr/local/src/ngx_cache_purge
# 重新編譯 Nginx(保持原有參數,新增 --add-module)
cd /usr/local/src/nginx-1.24.0
./configure --prefix=/usr/local/nginx \
--user=www --group=www \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_gzip_static_module \
--add-module=/usr/local/src/ngx_cache_purge \
...(其他原有參數)
make && make install
# 平滑升級
kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
sleep 2
kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`
# 清除單個 URL 緩存
curl -X PURGE https://www.example.com/static/logo.png
# 或 GET 請求(配置支援)
curl https://www.example.com/purge/static/logo.png
# 批量清除(需 Lua 腳本或外部腳本遍歷)
# 例:清除 /static/ 目錄下所有
# 需配合 ngx_cache_purge 進階版或第三方模組
#!/bin/bash
# deploy.sh 片段
rsync -avz /build/static/ web1:/var/www/app/static/
rsync -avz /build/static/ web2:/var/www/app/static/
# 通知所有 Nginx 節點清除緩存
for nginx in nginx1 nginx2 nginx3; do
ssh $nginx "curl -s -X PURGE https://localhost/purge/static/ >/dev/null"
done
location ~* \.(gif|jpg|jpeg|png|bmp|swf)$ {
valid_referers none blocked *.example.com example.com;
if ($invalid_referer) {
rewrite ^ /403.jpg break;
}
# 文件不存在返回預設圖
if (!-f $request_filename) {
rewrite ^ /404.jpg last;
}
expires 30d;
proxy_cache tomcat_cache;
proxy_pass https://tomcat_backend;
}
location = /403.jpg { root /var/www/app; access_log off; }
location = /404.jpg { root /var/www/app; access_log off; }
# http 上下文
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=app_cache:200m inactive=30d max_size=100g use_temp_path=off;
proxy_temp_path /data/nginx/tmp;
proxy_cache_key "$scheme$request_method$host$request_uri$is_args$args";
proxy_cache_valid 200 302 30d;
proxy_cache_valid 404 1m;
proxy_cache_min_uses 1;
proxy_cache_methods GET HEAD;
upstream tomcat_backend {
server 127.0.0.1:8080 weight=3 max_fails=3 fail_timeout=30s;
server 10.0.1.2:8080 weight=2 max_fails=3 fail_timeout=30s;
keepalive 128;
}
server {
listen 80;
server_name www.example.com;
# 通用代理參數
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-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Connection "";
# 靜態資源:代理緩存 + 防盜鏈 + 404 佔位
location ~* \.(gif|jpg|jpeg|png|bmp|swf|css|js|ico|woff2?|svg)$ {
valid_referers none blocked *.example.com example.com;
if ($invalid_referer) { rewrite ^ /403.jpg break; }
if (!-f $request_filename) { rewrite ^ /404.jpg last; }
proxy_cache app_cache;
proxy_pass https://tomcat_backend;
expires 30d;
add_header X-Cache-Status $upstream_cache_status;
}
# 動態應用:不緩存
location / {
proxy_cache off;
proxy_pass https://tomcat_backend;
}
# 手動清除
location ~ /purge(/.*) {
allow 10.0.0.0/8; allow 127.0.0.1; deny all;
proxy_cache_purge app_cache "$scheme$request_method$host$1$is_args$args";
}
# 佔位圖
location = /403.jpg { root /var/www/app; internal; }
location = /404.jpg { root /var/www/app; internal; }
}
| 坑點 | 現象 | 解決 |
|---|---|---|
proxy_temp_path 與 proxy_cache_path 不在同一檔案系統 | 緩存寫入失敗,日誌 rename() failed: Invalid cross-device link | 兩者必須同掛載點,或設 use_temp_path=off(Nginx 1.7+)直接寫入緩存目錄 |
proxy_cache_key 缺少 $args | 不同查詢參數返回同一緩存(如 /api?page=1 和 ?page=2 內容相同) | 鍵中包含 $is_args$args |
| 動態頁面被誤緩存 | 用戶看到他人個人資訊、購物車混亂 | proxy_cache_off 或 proxy_no_cache $cookie_sessionid 精準排除 |
| PURGE 請求被緩存 | 清除 API 本身被緩存,導致後續 PURGE 失效 | location /purge { proxy_cache off; ... } |
| 防盜鏈誤殺正常引用 | 自家 App/WebView/郵件客戶端無 Referer 被擋 | valid_referers none blocked ... 允許無 Referer |
Nginx 反向代理進階三部曲:動靜分離(架構層) → proxy_cache 緩存(效能層) → ngx_cache_purge 失效(運維層)。掌握三種分離模式適用場景、緩存鍵設計原則、手動失效整合發布流程、防盜鏈與佔位圖細節,即可構建高性能、可運維、安全可控的 Java Web 前端加速層。