Skip to content

05 · 反向代理 · Nginx 的灵魂技能

生活类比:反向代理就是酒店前台——你(用户)来住店,前台帮你联系不同部门:客房部、餐饮部、会议室。你只跟前台打交道,根本不知道后面有几个人在服务

这一章是 Nginx 真正的"杀手锏"——前端 / 后端 / 运维都必须吃透。


1. 正向代理 vs 反向代理 · 一图分清

┌────────── 正向代理(代理客户端)──────────┐
│                                              │
│  你 ──► 翻墙 VPN ──► Google                  │
│         (帮你绕墙)                            │
│                                              │
└──────────────────────────────────────────────┘

┌────────── 反向代理(代理服务器)──────────┐
│                                              │
│  用户 ──► Nginx ──► 真正的后端服务            │
│         (隐藏后端)                          │
│                                              │
└──────────────────────────────────────────────┘
维度正向代理反向代理
谁知道存在客户端知道,服务端不知服务端知道,客户端不知
配置在哪客户端服务端入口
典型例子VPN、公司出网代理Nginx、CDN、API 网关

一句话记忆:正向代客反向代服


2. 最简反向代理(30 秒上手)

场景:浏览器请求 /api/users → 转发到本机 Node 服务(端口 3000)

nginx
location /api/ {
    proxy_pass http://127.0.0.1:3000/;
}

整个 Nginx 配置就这一行核心指令:proxy_pass

⚠️ 但生产环境只写这一行远远不够——下面会讲完整套路。


3. proxy_pass 的"斜杠玄学"⚠️

这是 Nginx 第一个能让人秃头的小坑。

4 种写法 · 对比

假设请求是 GET /api/users/1

配置真正打到后端的 URL标记
location /api/ → proxy_pass http://b/http://b/users/1✅ 截掉前缀
location /api/ → proxy_pass http://bhttp://b/api/users/1✅ 保留前缀
location /api → proxy_pass http://b/http://b//users/1(坑!)❌ 多个斜杠
location /api → proxy_pass http://bhttp://b/api/users/1✅ 保留前缀

口诀

  • proxy_pass URL 末尾有 / → Nginx 会把 location 前缀截掉再拼路径
  • proxy_pass URL 末尾没 / → Nginx 把完整 URL 透传过去

生活类比

  • /:前台说"给二楼工程部",但只把"用户问题"转过去(改写过的需求单
  • /:前台说"给二楼工程部",把整张原始需求单直接转过去

4. 必加的 5 个 proxy_set_header

问题:经过 Nginx 的请求,后端拿到的 client IP 永远是 Nginx 自己!日志、风控、限流全废。

解决:转发时手动塞几个头,把"原始信息"传给后端:

nginx
location /api/ {
    proxy_pass http://127.0.0.1:3000/;

    proxy_set_header Host              $host;                   # ① 原始域名
    proxy_set_header X-Real-IP         $remote_addr;            # ② 原始客户端 IP
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for; # ③ 链路 IP 列表
    proxy_set_header X-Forwarded-Proto $scheme;                 # ④ http 还是 https
    proxy_set_header X-Forwarded-Host  $host;                   # ⑤ 原始 Host
}
Header作用
Host后端看到原始域名,否则会拿到 127.0.0.1:3000
X-Real-IP后端拿用户真实 IP(最简单)
X-Forwarded-For经过的代理链 IP 列表(标准做法)
X-Forwarded-Proto后端知道用户访问的是 http 还是 https
X-Forwarded-Host同 Host,备用

后端读 IP 的伪代码(Node.js / Express):

js
const realIp =
    req.headers['x-real-ip'] ||
    (req.headers['x-forwarded-for'] || '').split(',')[0].trim() ||
    req.socket.remoteAddress;

⚠️ 安全注意X-Forwarded-For 是请求头,用户可以伪造!只有"信任的代理"传过来的才能采信。详见 qa.md 第 14 题。


5. 超时控制 · 别让一个慢接口拖垮整个 Nginx

nginx
location /api/ {
    proxy_pass http://backend/;

    proxy_connect_timeout 5s;     # 连后端最多等 5 秒
    proxy_send_timeout    30s;    # 发请求体到后端最多等 30 秒
    proxy_read_timeout    30s;    # 读后端响应最多等 30 秒
}
指令默认推荐
proxy_connect_timeout60s5s(建连应该极快)
proxy_send_timeout60s30s
proxy_read_timeout60s30s(业务慢可放宽到 60s)

长连接 / WebSocket 业务要单独大幅放宽 read_timeout,下面讲。


6. WebSocket 反向代理(必考)

WebSocket 是基于 HTTP 的"协议升级"——浏览器先 GET,请求头里带 Upgrade: websocket,让服务器把 TCP 连接"升级"成 WS。

nginx
location /ws/ {
    proxy_pass http://127.0.0.1:4000/;

    proxy_http_version 1.1;                       # ① 必须 HTTP/1.1
    proxy_set_header Upgrade    $http_upgrade;    # ② 透传 Upgrade
    proxy_set_header Connection "upgrade";        # ③ 改 Connection 为 upgrade

    proxy_read_timeout 3600s;                     # ④ 长连接,把超时拉长
}

少任何一个 → WebSocket 第一时间断开,新人 90% 的"WebSocket 连不上"问题都在这。


7. 给前端跨域的优雅解法 · 让 Nginx 兜跨域

前端访问 /api/users 时,浏览器认为这是"同源"(因为前端域名也是 app.example.com),不会触发跨域。Nginx 在背后偷偷转发到后端 → 完美解决跨域问题。

传统方案:           前端 (app.com) ─跨域─► 后端 (api.com)
                                      └─ 后端要配 CORS

Nginx 反代方案:    前端 (app.com)        ┌─► /        → 静态文件
                       │                    │
                       └──► Nginx ─────────┤
                                            └─► /api/   → 转给 api.com(同源,无跨域)
nginx
server {
    server_name app.example.com;

    location / {
        root /var/www/myapp;
        try_files $uri $uri/ /index.html;
    }

    location /api/ {
        proxy_pass http://api.example.com/;     # 后端在另一个域,nginx 内部转发
        # ... 标准 5 个 proxy_set_header ...
    }
}

前端请求时直接写 fetch('/api/users') —— 既无跨域、又不需要后端配 CORS。这是中小项目最常用的解法。


8. 透传上传请求(大文件 / multipart)

nginx
location /api/upload {
    proxy_pass http://backend/upload;

    client_max_body_size 100m;            # 默认 1m,太小!
    proxy_request_buffering off;          # 别在 Nginx 这缓存整个文件再发,直接流式转发
}

proxy_request_buffering off 的好处:上传 1GB 文件不会先把 1GB 攒在 nginx 内存里。


9. 实战模板:完整的 SPA + API + WS 配置

nginx
upstream api_backend {
    server 127.0.0.1:3000;
    keepalive 64;     # 与后端保持长连接,提速
}

server {
    listen 80;
    server_name app.example.com;

    root /var/www/myapp;

    # 1. SPA
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 2. API
    location /api/ {
        proxy_pass http://api_backend/;
        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 5s;
        proxy_read_timeout    30s;
    }

    # 3. WebSocket
    location /ws/ {
        proxy_pass http://127.0.0.1:4000/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade    $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host       $host;
        proxy_read_timeout 3600s;
    }
}

10. ⚠️ 反向代理 7 大踩坑总结

  1. proxy_pass 末尾斜杠 → 见第 3 节"斜杠玄学"
  2. 后端拿不到真实 IP → 没设 X-Real-IP / X-Forwarded-For
  3. WebSocket 连不上 → 没配 Upgrade 三件套
  4. upload 413client_max_body_size 没改
  5. 后端 Host 是 127.0.0.1:3000 → 没设 proxy_set_header Host $host
  6. 后端日志显示请求是 http,但用户用的 https → 没设 X-Forwarded-Proto
  7. X-Forwarded-For 被用户伪造 → 入口的 Nginx 应该重置这个头:proxy_set_header X-Forwarded-For $remote_addr;

11. 章末面试题速览

详见 qa.md 第 12-15 题。

  1. 正向代理 vs 反向代理? → 正向代客户端、反向代服务器。
  2. proxy_pass 末尾的 / 有什么影响? → 有 / 会截掉 location 前缀,没 / 透传完整 URL。
  3. 怎么让后端拿到真实 IP?proxy_set_header X-Real-IP $remote_addr;
  4. Nginx 代理 WebSocket 要注意啥?proxy_http_version 1.1 + Upgrade / Connection "upgrade" + 拉长 read_timeout

12. 一句话总结

反向代理 = 把请求转给后端:核心一行 proxy_pass、必加 5 个 header、记牢"末尾斜杠玄学"——这就是 Nginx 80% 的工作内容。

下一章 → 06 · 负载均衡:把请求平均分给多台后端。

🎬 可视化演示

下方 demo 模拟反向代理:你在浏览器请求 /api/...,看 Nginx 怎么把请求 + headers 重写后发给后端,再把响应一路传回浏览器。

🎬 可视化演示

演示加载缓慢或样式异常?点此在新标签页打开 ↗