Files

4.7 KiB
Raw Permalink Blame History

id, title, type, domain, stack, tags, level, est_hours, related, week, order
id title type domain stack tags level est_hours related week order
devops.nginx.proxy-static 反向代理、负载均衡和静态资源:location 匹配、proxy_pass、SPA 回退 lesson devops
nginx
反向代理
location
proxy_pass
upstream
try_files
gzip
basic 2
devops.nginx.https-stream-limit
devops.nginx.interview
3
7
1

反向代理、负载均衡和静态资源:location 匹配、proxy_pass、SPA 回退

解释说明

  • 正向代理 vs 反向代理:正向代理代表客户端(翻墙代理),服务器不知道真实客户端;反向代理代表服务端,客户端只看到 Nginx,不知道后面有几台服务器。
  • 配置结构:http → server(按域名和端口区分站点)→ location(按路径匹配)。
  • location 匹配优先级:= 精确匹配最高;然后找最长的前缀匹配,如果它带 ^~ 就直接用;否则按配置顺序检查正则(~ 区分大小写、~* 不区分),第一个匹配的正则胜出;都不匹配就用最长前缀。
  • proxy_pass 末尾的斜杠:location /api/ { proxy_pass http://backend; } 会把 /api/users 原样转发;proxy_pass http://backend/;(带路径)会把匹配的 /api/ 替换成 /,后端收到 /users。
  • 转发真实客户端信息:后端看到的来源 IP 是 Nginx,要通过 X-Real-IP、X-Forwarded-For、X-Forwarded-Proto 传递;后端框架要配置信任这个代理(Gin 的 SetTrustedProxies、Uvicorn 的 --forwarded-allow-ips)。
  • 负载均衡:upstream 中列多个 server,默认轮询;还有 weight 权重、least_conn 最少连接、ip_hash 同一 IP 固定到同一台。max_fails / fail_timeout 做被动健康检查。
  • 静态资源:root 拼接路径(root /var/www; + /a.js → /var/www/a.js),alias 替换路径;SPA 用 try_files $uri $uri/ /index.html; 把前端路由回退到 index.html;带哈希的静态文件设长缓存,index.html 不缓存;开启 gzip。

案例

前后端分离部署在一台服务器:/ 是 Vue / React 打包后的静态文件,/api/ 转发到两台 Go API 实例,/ai/ 转发到 Python AI 服务。刷新 /orders/42 时出现 404,原因是没有配置 try_files 回退。

代码示例

upstream api {
    least_conn;
    server 127.0.0.1:8081 max_fails=3 fail_timeout=10s;   # 示例:两个后端实例
    server 127.0.0.1:8082 max_fails=3 fail_timeout=10s;
    keepalive 32;                                           # 和后端保持长连接
}

server {
    listen 80;
    server_name example.com;

    root /var/www/app/dist;
    gzip on;
    gzip_types text/css application/javascript application/json image/svg+xml;

    location / {
        try_files $uri $uri/ /index.html;                   # SPA 前端路由回退
    }
    location = /index.html {
        add_header Cache-Control "no-cache";                # 入口文件不缓存,发版立即生效
    }
    location /assets/ {
        expires 1y;                                         # 文件名带哈希,可以长缓存
        add_header Cache-Control "public, immutable";
    }

    location /api/ {
        proxy_pass http://api;                              # 不带路径:/api/users 原样转发
        proxy_http_version 1.1;
        proxy_set_header Connection "";                     # 配合 keepalive
        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_connect_timeout 3s;
        proxy_read_timeout 30s;
    }
}

可在本机用真实 Nginx 验证的完整配置和测试见 examples/gateway。修改配置后先 nginx -t 检查语法,再 nginx -s reload 平滑重载。

易错点

  • proxy_pass 带不带斜杠搞混:后端收到的路径多了或少了 /api,表现为 404。
  • root 和 alias 搞混:location /static/ { alias /data/files/; } 中 alias 末尾的斜杠要和 location 一致。
  • SPA 没配 try_files:刷新非首页路由 404。
  • index.html 被长缓存:发版后用户还在用旧页面、引用已删除的旧资源。
  • 后端拿到的 IP 全是 Nginx 的:没传 X-Forwarded-For 或后端没配置可信代理;反过来,盲目信任该头会被伪造。
  • 改完配置直接 reload 不先 nginx -t:语法错误时 reload 失败(旧配置继续运行),但如果是 restart 就直接起不来了。

面试常问

见 Nginx 面试题:正向和反向代理、location 优先级、负载均衡策略、proxy_pass 斜杠问题。