☰
Nginx 反向代理前端与后端:完整调用流程
2026/10/1 7:48:09 网站建设 项目流程

Nginx 反向代理前端与后端:完整调用流程

1. 背景

在典型的前后端分离项目中,前端通常使用 Vue、React
等框架开发,构建后生成静态文件;后端则由 Spring Boot、Node.js、Go
等服务提供 API。

生产环境中经常使用 Nginx 作为统一入口:

  • 对外暴露 HTTP/HTTPS 服务;
  • 提供前端静态资源;
  • 将/api/等接口请求反向代理到后端服务;
  • 隐藏后端真实地址和端口;
  • 统一处理 HTTPS、访问日志、超时、请求头等配置。

本文以以下部署结构为例:

Browser | | https://www.example.com v +-------------------+ | Nginx | | :80/443 | +---------+---------+ | +---- /、/assets/* ------> Frontend Static Files | index.html / JS / CSS | +---- /api/* ------------> Backend Service Spring Boot :8080

核心理解:对于浏览器端 SPA(Vue/React)来说,并不是"Nginx
把请求先转给前端服务,再由前端服务调用后端"。前端静态文件下载到浏览器后,JavaScript
在浏览器中执行;浏览器再次向 Nginx 发起 API 请求,Nginx 再将 API
请求代理到后端。


2. 示例部署

假设系统部署如下:

Domain: https://www.example.com Nginx: 80 / 443 Frontend: /var/www/frontend Backend: http://127.0.0.1:8080 API Prefix: /api/

前端构建产物:

/var/www/frontend/ ├── index.html └── assets/ ├── index.js └── index.css

一个典型的 Nginx 配置:

server { listen 80; server_name www.example.com; # Frontend location / { root /var/www/frontend; try_files $uri $uri/ /index.html; } # Backend API location /api/ { proxy_pass http://127.0.0.1:8080/; 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; } }

前端请求:

axios.get('/api/users')

3. 完整调用流程

整个流程可以拆成两个阶段:

  1. 浏览器获取并加载前端页面;
  2. 浏览器中的前端 JavaScript 调用后端 API。

完整链路:

┌─────────────┐ │ Browser │ └──────┬──────┘ │ │ ① GET / ▼ ┌─────────────┐ │ Nginx │ └──────┬──────┘ │ │ ② 查找前端静态资源 ▼ /var/www/frontend/index.html │ │ ③ 返回 HTML ▼ ┌─────────────┐ │ Browser │ └──────┬──────┘ │ │ ④ GET /assets/index.js │ GET /assets/index.css ▼ ┌─────────────┐ │ Nginx │ └──────┬──────┘ │ │ ⑤ 返回 JS/CSS ▼ ┌─────────────────────────┐ │ Browser executes JS │ │ Vue / React application │ └────────────┬────────────┘ │ │ ⑥ GET /api/users ▼ ┌─────────────┐ │ Nginx │ └──────┬──────┘ │ │ ⑦ proxy_pass ▼ ┌─────────────┐ │ Backend │ │ :8080 │ └──────┬──────┘ │ │ ⑧ JSON Response ▼ ┌─────────────┐ │ Nginx │ └──────┬──────┘ │ │ ⑨ JSON Response ▼ ┌─────────────┐ │ Browser │ └──────┬──────┘ │ │ ⑩ Vue/React 更新状态和 DOM ▼ 页面更新

4. 第一阶段:浏览器访问前端

4.1 用户输入域名

用户访问:

https://www.example.com/

经过 DNS 解析后,请求到达服务器上的 Nginx。

请求可以简化为:

GET / HTTP/1.1 Host: www.example.com

4.2 Nginx 匹配location /

Nginx 配置:

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

请求 URI 为:

/

因此进入location /。

对于 SPA 项目,try_files很重要:

try_files $uri $uri/ /index.html;

其含义可以理解为:

先查找请求对应的文件 | +-- 文件存在 --> 直接返回 | +-- 目录存在 --> 使用目录 | +-- 都不存在 --> 返回 /index.html

这使 Vue Router、React Router 使用 History 模式时,即使直接访问:

/user/1001

Nginx 也可以回退到:

/index.html

之后由前端路由决定展示哪个页面。


5. 第二阶段:浏览器加载 JS 和 CSS

浏览器拿到index.html后,会解析其中的资源,例如:

<scripttype="module"src="/assets/index.js"></script><linkrel="stylesheet"href="/assets/index.css">

浏览器继续发送请求:

GET /assets/index.js GET /assets/index.css

请求仍然是:

Browser | v Nginx

Nginx 找到对应静态文件后直接返回:

Browser | | GET /assets/index.js v Nginx | | /var/www/frontend/assets/index.js v Browser

此时 Vue/React 的 JavaScript 才真正开始在用户浏览器中运行。


6. 第三阶段:前端调用后端 API

假设页面初始化后需要查询用户列表:

axios.get('/api/users')

这段代码运行的位置是浏览器,而不是 Nginx,也不是服务器上的前端目录。

因此实际产生的是新的 HTTP 请求:

GET /api/users HTTP/1.1 Host: www.example.com

完整地址实际上是:

https://www.example.com/api/users

调用方向:

Browser | | GET /api/users v Nginx

7. 第四阶段:Nginx 将 API 请求反向代理到后端

Nginx 收到:

/api/users

由于配置了:

location /api/ { proxy_pass http://127.0.0.1:8080/; }

因此该请求匹配/api/,不会按照前端静态资源处理,而是执行反向代理。

在这个配置下,请求大致变成:

Browser | | GET /api/users v Nginx | | GET /users v 127.0.0.1:8080

后端只需要监听内部端口:

127.0.0.1:8080

客户端不需要知道后端真实 IP、端口或内部拓扑。


8. 第五阶段:后端处理业务

以 Spring Boot 为例,如果 Nginx 将/api/users转换成
/users,后端可以定义:

@RestControllerpublicclassUserController{@GetMapping("/users")publicList<User>users(){returnuserService.list();}}

后端内部可能继续执行:

Controller | v Service | v Repository / Mapper | v Database

例如:

Nginx | v Controller | v UserService | v UserMapper | v MySQL

数据库查询结束后,数据逐层返回,最终由后端序列化为 JSON:

[{"id":1,"name":"Tom"},{"id":2,"name":"Jerry"}]

9. 第六阶段:响应原路返回

后端不会直接把响应发送给浏览器。

由于 HTTP 连接是 Nginx 与后端建立的,因此响应首先回到 Nginx:

Backend | | HTTP Response + JSON v Nginx

然后 Nginx 再把响应发送给浏览器:

Backend | | JSON v Nginx | | JSON v Browser

因此完整 API 链路是:

Browser | | GET /api/users v Nginx | | GET /users v Backend | | Query v Database | | Result v Backend | | JSON v Nginx | | JSON v Browser

浏览器中的 Vue/React 获取 JSON 后更新状态,最终重新渲染页面。


10. 一张图理解整个系统

Internet | v +-------------------+ | Nginx | | :80/443 | +---------+---------+ | +-------------+-------------+ | | location / location /api/ | | v v +-------------------+ +-------------------+ | Frontend Static | | Backend Service | | index.html | | Spring Boot | | JS / CSS | | :8080 | +-------------------+ +---------+---------+ | v +-------------------+ | Database | | MySQL | +-------------------+

从浏览器角度看:

GET https://www.example.com/ | +--> Nginx --> index.html GET https://www.example.com/assets/index.js | +--> Nginx --> index.js GET https://www.example.com/api/users | +--> Nginx --> Backend --> Database

Nginx 根据请求 URI 完成流量分发。


11.proxy_pass最容易踩的坑:末尾/

这是 Nginx 反向代理配置中非常重要的一点。

情况 A:proxy_pass带/

location /api/ { proxy_pass http://127.0.0.1:8080/; }

客户端请求:

/api/users

通常转发为:

http://127.0.0.1:8080/users

也就是说,匹配到的/api/前缀被替换为/。

情况 B:proxy_pass不带/

location /api/ { proxy_pass http://127.0.0.1:8080; }

客户端请求:

/api/users

通常转发为:

http://127.0.0.1:8080/api/users

可以简单记忆:

location /api/ { proxy_pass http://backend/; } ^ 有 / /api/users ----------> /users

而:

location /api/ { proxy_pass http://backend; } ^ 无 / /api/users ----------> /api/users

因此配置 Nginx 时,必须和后端 Controller 的路径设计保持一致。


12. 为什么这种方式通常没有 CORS 问题

假设不使用 Nginx 统一代理,前端页面是:

https://www.example.com

而前端直接访问:

http://api.example.com:8080/users

浏览器看到的是两个不同的 Origin,可能涉及跨域资源共享(CORS)配置。

使用 Nginx 后,浏览器只看到:

https://www.example.com/ https://www.example.com/api/users

两者协议、主机和端口一致,因此从浏览器视角属于同源请求。

需要注意:这是因为浏览器请求的是 Nginx 的/api/...地址。Nginx
在服务器内部继续访问127.0.0.1:8080不属于浏览器跨域检查的范畴。


13. 请求头与真实客户端 IP

Nginx 作为反向代理后,后端直接建立连接的一方是 Nginx,而不是用户浏览器。

因此通常会配置:

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;

常见含义:

Header 作用


Host保留客户端访问的 Host
X-Real-IP传递客户端 IP
X-Forwarded-For记录代理链上的客户端 IP
X-Forwarded-Proto告诉后端原始请求是 HTTP 还是 HTTPS

链路可以理解为:

Browser (Client IP) | v Nginx | | X-Real-IP: Client IP | X-Forwarded-For: Client IP, ... v Backend

后端是否以及如何信任这些
Header,应结合实际代理拓扑和安全配置决定,避免直接信任来自非可信代理的伪造转发头。


14. Nginx 在整个架构中的角色

Nginx 并不是业务代码的一部分,它更像系统入口和流量调度层。

+----------------+ | Client | +-------+--------+ | v +----------------+ | Nginx | +-------+--------+ | +-------------+-------------+ | | | v v v Frontend Backend A Backend B Static /api/user /api/order

Nginx 可以承担:

  • 静态资源服务器;
  • 反向代理;
  • HTTPS/TLS 终止;
  • API 路由;
  • 负载均衡;
  • 请求头处理;
  • 超时控制;
  • 访问日志;
  • 压缩和缓存;
  • 限流等入口层能力。

15. 常见错误理解

误区 1:前端服务器调用后端

错误理解:

Browser | v Frontend | v Backend

对于构建后部署为静态文件的 Vue/React SPA,这通常不准确。

更准确的是:

Browser | +---- GET / ----------> Nginx --> Frontend Static Files | +---- GET /api/users -> Nginx --> Backend

前端 JavaScript 已经下载到浏览器,并在浏览器中执行。

如果使用 Next.js SSR、Nuxt SSR、BFF
等服务端渲染或服务端中间层架构,则调用链可能不同,不能套用纯 SPA
模型。

误区 2:Nginx 收到所有请求都会交给后端

不是。

Nginx 会根据location匹配规则决定如何处理:

/ ├── /assets/index.js --> static file ├── /login --> index.html (SPA fallback) └── /api/users --> backend

误区 3:后端响应直接返回浏览器

使用反向代理时,通常是:

Backend --> Nginx --> Browser

而不是:

Backend -------------> Browser

Nginx 是这一 HTTP 代理链路中的中间节点。


16. 排查问题时如何定位

遇到"页面正常但接口请求失败"时,可以按照调用链逐层排查:

Browser | | ① 请求是否正确? v Nginx | | ② location 是否匹配? | ③ proxy_pass URI 是否正确? v Backend | | ④ Controller 路径是否正确? | ⑤ 服务是否正常? v Database

浏览器层

打开浏览器 DevTools → Network,检查:

Request URL Request Method Status Code Request Headers Response Headers Response Body

尤其确认实际请求是不是:

https://www.example.com/api/users

而不是意外请求到其他域名或端口。

Nginx 层

检查配置:

nginx-t

查看访问日志和错误日志,例如:

access.log error.log

重点确认:

/api/users

是否进入预期的location /api/。

后端层

确认后端服务端口:

127.0.0.1:8080

在服务器内部可以直接验证:

curlhttp://127.0.0.1:8080/users

如果直接访问后端成功,而通过:

https://www.example.com/api/users

失败,问题通常集中在 Nginx 路由、URI 重写、代理配置或网络连接层。


17. HTTP 状态码快速定位

常见现象可以辅助判断问题所在:

现象 常见排查方向


404URI、location、proxy_pass路径或后端 Controller
502 Bad Gateway后端未启动、地址/端口错误、连接失败
504 Gateway Timeout后端处理过慢、网络问题、代理超时
403Nginx 权限、安全规则或后端鉴权
CORS Error 浏览器实际请求是否仍然跨 Origin
页面刷新 404 SPAtry_files配置
API 返回 HTML API 请求可能被错误地落入前端location

这些只是常见方向,最终仍应结合 Nginx 日志、后端日志和浏览器 Network
信息判断。


18. 最终总结

整个调用过程可以浓缩为两条链路。

前端资源加载

Browser | | GET / v Nginx | | Static File v index.html / JS / CSS | v Browser executes Vue/React

API 调用

Browser JavaScript | | GET /api/users v Nginx | | Reverse Proxy v Backend | | SQL v Database | v Backend | | JSON v Nginx | | JSON v Browser | v Vue/React renders UI

一句话概括:

Nginx 是统一入口:前端静态资源请求由 Nginx 直接返回,API 请求由
Nginx 反向代理到后端;前端 JavaScript
实际运行在浏览器中,后端响应再通过 Nginx 原路返回浏览器。


19. 推荐的理解模型

以后看到类似配置:

location / { root /var/www/frontend; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/; }

可以直接在脑中转换为:

+--> / --> Frontend | Browser --> Nginx --+ | +--> /api/* --> Backend

这就是 Nginx 在典型前后端分离 SPA 架构中的核心调用模型。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询