✅ 什么是反向代理?
🔹 代理:本质上是中间人,客户端和服务器之间的“中转站”。
🔹 代理分为:
- 正向代理:代理客户端,客户端通过代理去访问服务器。例如科学上网、公司网络代理。
- 反向代理:代理服务器,客户端并不知道真正的后端服务器是谁,它只知道代理服务器的 IP 和域名。
在反向代理中:
- 客户端 请求 Nginx;
- Nginx 接收请求并将其转发 到后端服务器(upstream),拿到后端响应后再转发给客户端。
客户端始终认为自己只和 Nginx 通信,而不知道真实服务器的存在。
🔎 Nginx 反向代理的工作流程
1️⃣ 浏览器(或客户端)向 Nginx 发起请求:
Client --> Nginx
2️⃣ Nginx 根据配置文件(nginx.conf)中的代理规则,决定把请求转发到哪个后端服务器:
Nginx --> Backend Server (e.g., app01, app02)
3️⃣ 后端服务器处理请求后,将结果返回给 Nginx:
Backend Server --> Nginx
4️⃣ Nginx 将后端的响应再传给客户端:
Nginx --> Client
整个过程:
- 对客户端来说,请求和响应都是和 Nginx 交互。
- Nginx 对后端服务器起到了隐藏、防护、负载均衡的作用。
🛠 原理核心:为什么需要反向代理?
- 安全性:隐藏真实服务器 IP,防止直接攻击后端。
- 负载均衡:可以分发请求到多台后端,实现水平扩展。
- 缓存能力:Nginx 可以缓存后端返回的静态资源,减轻后端负载。
- SSL 终止:Nginx 负责 HTTPS 解析,后端可用 HTTP 简化配置。
- 统一入口:对外提供单一域名,后端可以有多种服务(微服务架构场景)。
🔗 Nginx 反向代理配置示例
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass http://backend_servers; # 定义上游服务器组
proxy_set_header Host $host; # 传递原始Host
proxy_set_header X-Real-IP $remote_addr; # 传递真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
upstream backend_servers {
server 192.168.1.100:8080;
server 192.168.1.101:8080;
}
- 当客户端访问
www.example.com,Nginx 根据proxy_pass把请求转发给 upstream 中定义的 2 台服务器,实现负载均衡。
⚙️ Nginx 如何实现反向代理的底层原理?
- 事件驱动(异步)模型:Nginx 使用 epoll/kqueue 等机制实现高并发处理,代理转发请求时不会阻塞主线程。
- 内核高效 I/O:Nginx 在代理转发中使用零拷贝技术(如
sendfile),减少内核态和用户态的切换,转发时性能极高。 - 模块化设计:反向代理能力来自
ngx_http_proxy_module模块,灵活配置 proxy_pass、proxy_set_header 等指令。
✅ 应用场景
✔ 网站或 API 服务统一入口:前端请求通过 Nginx 反向代理到不同微服务
✔ 多服务器负载均衡:对接多台后端服务器,平滑分流
✔ HTTPS 加速与安全:由 Nginx 处理 SSL 协议,后端只需要 HTTP
✔ 静态资源加速:Nginx 对静态文件提供缓存能力
🔒 与正向代理的区别
| 类型 | 代理对象 | 客户端视角 | 使用场景 |
|---|---|---|---|
| 正向代理 | 客户端 | 客户端主动使用代理访问外网 | 科学上网、访问被封锁网站 |
| 反向代理 | 服务器 | 客户端无感知,只知道代理服务器域名 | 负载均衡、隐藏服务器、SSL 终止 |
🎯 场景:你的网站需要负载均衡
假设你有一个域名:
https://www.myapp.com
你的后端服务有两台机器:
- 192.168.1.101:8080
- 192.168.1.102:8080
这两台机器跑着相同的 Web 应用程序,你希望:
✅ 所有用户访问 www.myapp.com 时,都通过 Nginx
✅ Nginx 自动把请求平均分配到后端的两台服务器(负载均衡)
✅ 用户看不到真实的后端地址
🚀 请求过程举例
1️⃣ 用户在浏览器输入:
https://www.myapp.com/home
2️⃣ 浏览器会向 DNS 请求域名解析到 IP,比如:
www.myapp.com --> 公网IP 1.2.3.4
3️⃣ 1.2.3.4 其实是 Nginx 服务器的公网 IP。
4️⃣ Nginx 收到请求 /home 后,根据配置:
upstream my_backend {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
}
server {
listen 80;
server_name www.myapp.com;
location / {
proxy_pass http://my_backend; # 转发到后端
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;
}
}
5️⃣ Nginx 这里配置了 my_backend upstream,里面有两台后端服务器。
6️⃣ 当 Nginx 接收到 /home 请求时:
- 会按轮询的方式把请求转发给 192.168.1.101:8080 或 192.168.1.102:8080
- 后端处理完后响应 HTML 页面给 Nginx
- Nginx 再把响应转发给用户
7️⃣ 用户只知道响应来自 www.myapp.com,对后端服务器 IP 完全不感知。
✅ 关键点
- 客户端只和 Nginx 通信:客户端无法直接访问后端,安全性更高。
- Nginx 在中间做负载均衡:请求均匀分配给多台后端,后端压力平衡。
- 隐藏后端服务器:后端 IP 不暴露在公网上。
- 还能做缓存:比如静态资源 JS/CSS 可直接由 Nginx 缓存后返回。
🔎 一个完整的示例流程
假设:
-
用户 A、B、C 先后访问同一个 URL:
- A --> Nginx --> 后端服务器 1
- B --> Nginx --> 后端服务器 2
- C --> Nginx --> 后端服务器 1
(轮询策略)
-
用户始终访问
www.myapp.com,不用关心后端有多少台服务器,也不用改变请求地址。
🔥 为什么这样好?
-
对客户端:
- 访问简单:只要域名,不需要记 IP
- 延迟更低:Nginx 可以缓存静态资源
-
对运维:
- 后端随时扩容或替换机器,只需要在 nginx.conf 改一下 upstream
- 后端不暴露公网,避免直接攻击
-
对性能:
- 高并发场景下,Nginx 高效转发,防止后端过载
✅ 通过这个例子,希望你能直观理解:
Nginx 反向代理就是帮你把用户的请求转发到后端服务器,同时提供负载均衡、隐藏后端、缓存、SSL 等功能,它是现代高性能网站架构的核心!
继续解释
✅ 1)location / 的含义
- 在 Nginx 中,
location /表示匹配所有以/开头的路径,也就是 所有请求都会进入这个 location。 - 所以像
/home、/api/data、/about等等路径,都会被location /捕获到。
✅ 2)为什么没有必要写 location /home
- 因为你想把网站的所有路径统一代理到后端服务,而不是只代理
/home。 - 如果你写了
location /home,只会代理/home路径及其子路径,比如/home/page,其他如/about或/contact就不会被这条规则处理,会返回 404 或命中其他 location。
✅ 3)请求示例
假设你的 Nginx 监听 www.myapp.com:
-
当用户访问
http://www.myapp.com/home-
浏览器请求路径是
/home -
因为
/home以/开头,所以匹配到location / -
于是 Nginx 把请求
/home转发给后端:proxy_pass http://my_backend; # 后端接收到的请求路径也是 /home
-
-
当用户访问
http://www.myapp.com/api/user- 浏览器请求路径是
/api/user - 也同样匹配到
location /,然后转发。
- 浏览器请求路径是
✅ 4)如何只代理 /home 路径
如果你只想把 /home 请求代理到后端,其他路径不转发,可以写:
location /home {
proxy_pass http://my_backend;
...
}
这样:
/home和/home/xxx会被转发。/api、/about等不会命中/homelocation,会继续往下匹配其他 location 块,或者直接返回 404。
✅ 5)保持请求路径的关键
proxy_pass 有一个容易忽略的坑:
-
当你写
proxy_pass http://my_backend;并且 location 是location /,会将请求路径原样传给后端。/home请求依然是/home到后端。
-
但是如果你写了:
location /home { proxy_pass http://my_backend/; }Nginx 会把匹配到的
/home部分 剥离掉,把后面的路径拼接到/后转发给后端。例如:- 用户请求
/home/page-> 后端收到/page(丢了/home)。
- 用户请求
-
这种行为经常引发“请求路径错位”的问题。
location /ws/ {
proxy_pass http://my_backend/ws/;
...
}
✅ 1)location /ws/ 匹配范围
-
location /ws/表示会匹配所有以/ws/开头的请求路径:/ws/home✅ 匹配/ws/page✅ 匹配/ws❌ 不匹配!注意/ws(没有结尾斜杠)不会命中/ws/,会去找是否有别的 location(比如location /ws),否则匹配不到就落到更上层 location(如location /)。
✅ 2)proxy_pass 拼接规则
Nginx 的 proxy_pass 在有 路径 时有一个非常重要的规律:
如果
proxy_pass后面带了路径部分,就会丢弃 location 块里匹配到的路径,并把请求的 URI 中 location 块后面的部分拼接到 proxy_pass 路径上。
来看你的例子:
location /ws/ {
proxy_pass http://my_backend/ws/;
}
-
这里的 location 是
/ws/,proxy_pass 是http://my_backend/ws/。 -
比如用户请求:
/ws/home/ws/是 location 匹配到的部分/home是请求中 location 后剩下的部分
-
按规则:
最终请求 = proxy_pass 中的路径部分 + location 后面的部分也就是:
最终请求 = /ws/ + home = /ws/home
✅ 所以你的例子中:
-
用户请求
/ws/home -
匹配到 location
/ws/ -
/ws/后的部分是/home -
拼接到
proxy_pass中的/ws/后:最终请求 = /ws/ + home = /ws/home -
后端实际收到的请求是:
http://192.168.1.101:8080/ws/home(其中 my_backend 会解析到 upstream 配置里的服务器地址)
✅ 3)为什么很多人会踩坑?
因为很多人会觉得:
我 location 和 proxy_pass 都写了
/ws/,是不是就会造成/ws/ws/...?
但实际上,Nginx 在有路径的 proxy_pass 时会丢弃匹配的 location 部分(/ws/),只拼接剩下的 URI 到 proxy_pass 的路径。
✅ 4)那什么时候会出现路径错位?
如果你写:
location /ws/ {
proxy_pass http://my_backend; # 注意,这里proxy_pass没有路径
}
因为这里 proxy_pass 没有路径部分,那么 Nginx 就会把 整个原始请求 URI(不丢弃 location)直接转发给后端。
例如:
- 请求
/ws/home - 最终后端收到
/ws/home
🔎 关键区别总结:
- proxy_pass 带路径:丢弃 location 匹配到的部分,拼接剩余 URI 到 proxy_pass 路径
- proxy_pass 不带路径:保留完整的原始请求 URI,原样转发
🔎 总结一句话:
- 你配置
location /是想把网站所有路径都代理到后端,/home属于/匹配范围,所以当然能正常转发到后端; - 如果只需要代理部分路径,才需要写
location /home; - 不要被
location块的语法迷惑,/是 Nginx 中“捕获所有路径”的通用方式。
🎯 总结一句话
反向代理就是:Nginx 作为中间人,接收客户端请求,转发给后端,并把响应返回给客户端,同时提供负载均衡、安全、缓存等能力,是现代网站和微服务架构的核心组件。