文章目录 前言 一、先搞懂一个关键概念反向代理1.1 没有 Nginx 时你是怎么访问的1.2 有了 Nginx 后发生了什么1.3 一张图看懂整体流程 二、两种部署方式下的 Nginx 配置详解2.1 方式一前后端分离部署⭐ 生产环境推荐✅ Nginx 配置文件 请求流程拆解2.2 方式二前后端一体化部署适合小项目/学习✅ Nginx 配置文件 请求流程拆解⚖️ 三、两种方式对比怎么选 四、关于跨域问题自动消失的原理 五、补充proxy_set_header 那几行到底在干嘛✍️ 总结 前言很多刚接触项目部署的小伙伴在本地开发时往往是这样操作的前端跑在localhost:3000或者 80 端口后端跑在localhost:8080中间搞个跨域配置玩得不亦乐乎。但是一到服务器部署面对 Nginx 就懵圈了“平时我访问localhost:8080/index.html才能看到页面配置了 Nginx 代理后凭什么我直接敲个域名或localhost就能直接访问了内部到底是怎么转发的”这个问题非常经典是每个后端/全栈开发必经的“顿悟时刻”。今天我们就用大白话把 Nginx 转发的底层逻辑扒个底朝天 一、先搞懂一个关键概念反向代理1.1 没有 Nginx 时你是怎么访问的你在浏览器里输入localhost:8080/index.html这意味着你直接和 Spring Boot 内嵌的 Tomcat 对话你必须知道它住在8080这个房间号如果前端部署在另一个端口比如3000还会遇到跨域问题类比一下就像你要找某个公司的张三你得自己知道他在18楼 808室然后自己坐电梯上去敲门。1.2 有了 Nginx 后发生了什么Nginx 就像公司大楼的前台接待员你只需要走到大门口localhost默认80端口前台会根据你的来意自动帮你转接想看网页→ 直接给你拿前端文件想调接口→ 帮你转接到后端8080你全程不需要知道任何房间号这就是所谓的反向代理Reverse Proxy——客户端不直接访问真实服务而是通过一个中间层Nginx来统一调度。1.3 一张图看懂整体流程┌─────────────────────────────────────────┐ │ Nginx监听 80 端口 │ │ │ 浏览器 │ 请求路径 转发目标 │ ──────────────────► │ / ──► 前端静态文件本地磁盘│ http://localhost/ │ /api/** ──► Spring Boot8080 │ http://localhost/api/* │ │ └─────────────────────────────────────────┘ │ │ ▼ ▼ ┌──────────────┐ ┌──────────────────┐ │ /var/www/ │ │ localhost:8080 │ │ html/my-app │ │ (Spring Boot) │ │ index.html │ │ /api/user/1 │ │ css/js/img │ │ /api/order/... │ └──────────────┘ └──────────────────┘ 二、两种部署方式下的 Nginx 配置详解实际项目中前端和后端的打包方式不同Nginx 的配置也不一样。下面分两种情况讲清楚。2.1 方式一前后端分离部署⭐ 生产环境推荐这是目前最主流的部署方式组件打包方式部署位置前端Vue/Reactnpm run build→ 生成dist目录复制到服务器/var/www/html/my-app后端Spring Bootmvn package→ 生成.jar文件java -jar app.jar监听8080Nginx—监听80端口负责调度✅ Nginx 配置文件# /etc/nginx/conf.d/my-app.conf server { # ① 监听 80 端口HTTP 默认端口浏览器输入域名时自动走这里 listen 80; server_name localhost; # 生产环境换成你的域名如 www.example.com # ② 前端静态资源所有非 API请求都走这里 location / { # 前端打包文件存放的目录 root /var/www/html/my-app; # 关键配置按顺序尝试 # 1. 精确匹配文件如 /css/style.css # 2. 匹配目录 # 3. 都没有回退到 index.htmlSPA 单页应用的路由全靠这个 try_files $uri $uri/ /index.html; } # ③ 后端 API 代理所有以 /api/ 开头的请求转发给 Spring Boot location /api/ { # 核心指令把请求转发到后端服务 proxy_pass http://localhost: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; } # ④ 错误页面可选 error_page 500 502 503 504 /50x.html; location /50x.html { root /usr/share/nginx/html; } } 请求流程拆解场景1用户打开首页用户输入http://localhost/ → 浏览器发起请求GET / → Nginx 匹配到 location / → 去 /var/www/html/my-app 目录找 index.html → 找到了直接返回给浏览器 ✅ → 浏览器渲染页面同时加载 CSS/JS 等静态资源同理走 location /场景2前端页面调用后端接口前端代码axios.get(/api/user/1) → 浏览器发起请求GET http://localhost/api/user/1 → Nginx 匹配到 location /api/更精确优先匹配 → Nginx 转发请求到 http://localhost:8080/api/user/1 → Spring Boot 处理请求返回 JSON 数据 → Nginx 拿到响应原样返回给浏览器 ✅注意整个过程中浏览器只和localhost:80Nginx通信完全不知道8080的存在。所以从浏览器视角看前端页面和 API 接口是同源的 ——跨域问题自然就不存在了2.2 方式二前后端一体化部署适合小项目/学习有些项目会把前端的 HTML/CSS/JS 直接放在 Spring Boot 的src/main/resources/static目录下然后一起打成一个 JAR 包。此时 Spring Boot既当爹又当妈既处理 API 请求又提供静态页面。Nginx 的工作就简单多了 ——当个传话筒所有请求无脑转发就行✅ Nginx 配置文件server { listen 80; server_name localhost; # 简单粗暴所有请求一律转发给 Spring Boot location / { proxy_pass http://localhost: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; } } 请求流程拆解用户输入http://localhost/ → Nginx 收到请求 GET / → 转发到 http://localhost:8080/ → Spring Boot 内嵌的 Tomcat 处理 → 返回 static/index.html 的内容 → Nginx 透传给浏览器 ✅ 前端调用axios.get(/api/user/1) → Nginx 收到请求 GET /api/user/1 → 转发到 http://localhost:8080/api/user/1 → Spring Boot 的 RestController 处理 → 返回 JSON → Nginx 透传给浏览器 ✅⚖️ 三、两种方式对比怎么选对比维度 前后端分离部署 前后端一体化部署Nginx 职责静态文件托管 API 转发纯转发传话筒Spring Boot 职责只管 API 业务逻辑API 静态文件啥都管静态资源性能⚡极快Nginx 天生擅长 较慢Tomcat 处理静态文件效率低部署灵活性✅ 前后端独立部署、独立更新❌ 改个前端样式都要重新打 JAR 包扩展性✅ 前后端可独立扩容❌ 只能整体扩容配置复杂度稍复杂需区分路径非常简单适用场景生产环境、团队协作个人小项目、学习练手结论生产环境强烈推荐前后端分离部署。Nginx 处理静态资源的能力是 Tomcat 的几十倍而且前后端解耦后团队协作效率会大幅提升。 四、关于跨域问题自动消失的原理很多同学好奇为什么配了 Nginx 之后前端调后端接口不再报跨域错误了这就要理解浏览器的同源策略Same-Origin Policy同源 协议 域名 端口三者完全一致场景前端地址API 地址是否同源没有 Nginxhttp://localhost:3000http://localhost:8080/api❌ 端口不同跨域有了 Nginxhttp://localhost(80)http://localhost/api(80)✅ 完全同源没问题关键在于浏览器看到的始终是localhost:80它根本不知道/api的请求被 Nginx 偷偷转发到了8080。在浏览器眼里一切都是同一个源。 五、补充proxy_set_header那几行到底在干嘛你可能注意到配置里总有这么几行透传头信息的代码很多人直接复制粘贴但不理解它的作用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;指令作用不加会怎样Host $host把原始请求的域名传给后端后端拿到的 Host 可能是localhost:8080而不是用户实际访问的域名X-Real-IP把客户端真实 IP 传给后端后端通过request.getRemoteAddr()拿到的是 Nginx 的 IP127.0.0.1而非用户真实 IPX-Forwarded-For记录整个代理链路的 IP多层代理时无法追溯请求来源X-Forwarded-Proto告诉后端原始请求是 HTTP 还是 HTTPS后端无法正确判断协议可能影响重定向逻辑一句话总结这几行配置确保后端能获取到用户的真实信息而不是 Nginx 代理服务器的信息。生产环境务必加上。✍️ 总结整篇文章的核心其实就一句话Nginx 反向代理 在浏览器和后端服务之间加了一个智能前台统一入口、按路径分发、隐藏内部细节。再回顾一下关键要点listen 80—— 让 Nginx 监听默认端口用户无需输入端口号location /—— 匹配前端静态资源请求location /api/—— 匹配后端 API 请求proxy_pass—— 核心指令实现请求转发try_files—— SPA 单页应用的救命配置保证前端路由正常工作同源效果—— 浏览器只看到80端口跨域问题自然消失
【部署实战】一文搞懂!SpringBoot + 前端项目上线,Nginx 到底是怎么做请求转发的?
发布时间:2026/5/25 9:17:31
文章目录 前言 一、先搞懂一个关键概念反向代理1.1 没有 Nginx 时你是怎么访问的1.2 有了 Nginx 后发生了什么1.3 一张图看懂整体流程 二、两种部署方式下的 Nginx 配置详解2.1 方式一前后端分离部署⭐ 生产环境推荐✅ Nginx 配置文件 请求流程拆解2.2 方式二前后端一体化部署适合小项目/学习✅ Nginx 配置文件 请求流程拆解⚖️ 三、两种方式对比怎么选 四、关于跨域问题自动消失的原理 五、补充proxy_set_header 那几行到底在干嘛✍️ 总结 前言很多刚接触项目部署的小伙伴在本地开发时往往是这样操作的前端跑在localhost:3000或者 80 端口后端跑在localhost:8080中间搞个跨域配置玩得不亦乐乎。但是一到服务器部署面对 Nginx 就懵圈了“平时我访问localhost:8080/index.html才能看到页面配置了 Nginx 代理后凭什么我直接敲个域名或localhost就能直接访问了内部到底是怎么转发的”这个问题非常经典是每个后端/全栈开发必经的“顿悟时刻”。今天我们就用大白话把 Nginx 转发的底层逻辑扒个底朝天 一、先搞懂一个关键概念反向代理1.1 没有 Nginx 时你是怎么访问的你在浏览器里输入localhost:8080/index.html这意味着你直接和 Spring Boot 内嵌的 Tomcat 对话你必须知道它住在8080这个房间号如果前端部署在另一个端口比如3000还会遇到跨域问题类比一下就像你要找某个公司的张三你得自己知道他在18楼 808室然后自己坐电梯上去敲门。1.2 有了 Nginx 后发生了什么Nginx 就像公司大楼的前台接待员你只需要走到大门口localhost默认80端口前台会根据你的来意自动帮你转接想看网页→ 直接给你拿前端文件想调接口→ 帮你转接到后端8080你全程不需要知道任何房间号这就是所谓的反向代理Reverse Proxy——客户端不直接访问真实服务而是通过一个中间层Nginx来统一调度。1.3 一张图看懂整体流程┌─────────────────────────────────────────┐ │ Nginx监听 80 端口 │ │ │ 浏览器 │ 请求路径 转发目标 │ ──────────────────► │ / ──► 前端静态文件本地磁盘│ http://localhost/ │ /api/** ──► Spring Boot8080 │ http://localhost/api/* │ │ └─────────────────────────────────────────┘ │ │ ▼ ▼ ┌──────────────┐ ┌──────────────────┐ │ /var/www/ │ │ localhost:8080 │ │ html/my-app │ │ (Spring Boot) │ │ index.html │ │ /api/user/1 │ │ css/js/img │ │ /api/order/... │ └──────────────┘ └──────────────────┘ 二、两种部署方式下的 Nginx 配置详解实际项目中前端和后端的打包方式不同Nginx 的配置也不一样。下面分两种情况讲清楚。2.1 方式一前后端分离部署⭐ 生产环境推荐这是目前最主流的部署方式组件打包方式部署位置前端Vue/Reactnpm run build→ 生成dist目录复制到服务器/var/www/html/my-app后端Spring Bootmvn package→ 生成.jar文件java -jar app.jar监听8080Nginx—监听80端口负责调度✅ Nginx 配置文件# /etc/nginx/conf.d/my-app.conf server { # ① 监听 80 端口HTTP 默认端口浏览器输入域名时自动走这里 listen 80; server_name localhost; # 生产环境换成你的域名如 www.example.com # ② 前端静态资源所有非 API请求都走这里 location / { # 前端打包文件存放的目录 root /var/www/html/my-app; # 关键配置按顺序尝试 # 1. 精确匹配文件如 /css/style.css # 2. 匹配目录 # 3. 都没有回退到 index.htmlSPA 单页应用的路由全靠这个 try_files $uri $uri/ /index.html; } # ③ 后端 API 代理所有以 /api/ 开头的请求转发给 Spring Boot location /api/ { # 核心指令把请求转发到后端服务 proxy_pass http://localhost: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; } # ④ 错误页面可选 error_page 500 502 503 504 /50x.html; location /50x.html { root /usr/share/nginx/html; } } 请求流程拆解场景1用户打开首页用户输入http://localhost/ → 浏览器发起请求GET / → Nginx 匹配到 location / → 去 /var/www/html/my-app 目录找 index.html → 找到了直接返回给浏览器 ✅ → 浏览器渲染页面同时加载 CSS/JS 等静态资源同理走 location /场景2前端页面调用后端接口前端代码axios.get(/api/user/1) → 浏览器发起请求GET http://localhost/api/user/1 → Nginx 匹配到 location /api/更精确优先匹配 → Nginx 转发请求到 http://localhost:8080/api/user/1 → Spring Boot 处理请求返回 JSON 数据 → Nginx 拿到响应原样返回给浏览器 ✅注意整个过程中浏览器只和localhost:80Nginx通信完全不知道8080的存在。所以从浏览器视角看前端页面和 API 接口是同源的 ——跨域问题自然就不存在了2.2 方式二前后端一体化部署适合小项目/学习有些项目会把前端的 HTML/CSS/JS 直接放在 Spring Boot 的src/main/resources/static目录下然后一起打成一个 JAR 包。此时 Spring Boot既当爹又当妈既处理 API 请求又提供静态页面。Nginx 的工作就简单多了 ——当个传话筒所有请求无脑转发就行✅ Nginx 配置文件server { listen 80; server_name localhost; # 简单粗暴所有请求一律转发给 Spring Boot location / { proxy_pass http://localhost: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; } } 请求流程拆解用户输入http://localhost/ → Nginx 收到请求 GET / → 转发到 http://localhost:8080/ → Spring Boot 内嵌的 Tomcat 处理 → 返回 static/index.html 的内容 → Nginx 透传给浏览器 ✅ 前端调用axios.get(/api/user/1) → Nginx 收到请求 GET /api/user/1 → 转发到 http://localhost:8080/api/user/1 → Spring Boot 的 RestController 处理 → 返回 JSON → Nginx 透传给浏览器 ✅⚖️ 三、两种方式对比怎么选对比维度 前后端分离部署 前后端一体化部署Nginx 职责静态文件托管 API 转发纯转发传话筒Spring Boot 职责只管 API 业务逻辑API 静态文件啥都管静态资源性能⚡极快Nginx 天生擅长 较慢Tomcat 处理静态文件效率低部署灵活性✅ 前后端独立部署、独立更新❌ 改个前端样式都要重新打 JAR 包扩展性✅ 前后端可独立扩容❌ 只能整体扩容配置复杂度稍复杂需区分路径非常简单适用场景生产环境、团队协作个人小项目、学习练手结论生产环境强烈推荐前后端分离部署。Nginx 处理静态资源的能力是 Tomcat 的几十倍而且前后端解耦后团队协作效率会大幅提升。 四、关于跨域问题自动消失的原理很多同学好奇为什么配了 Nginx 之后前端调后端接口不再报跨域错误了这就要理解浏览器的同源策略Same-Origin Policy同源 协议 域名 端口三者完全一致场景前端地址API 地址是否同源没有 Nginxhttp://localhost:3000http://localhost:8080/api❌ 端口不同跨域有了 Nginxhttp://localhost(80)http://localhost/api(80)✅ 完全同源没问题关键在于浏览器看到的始终是localhost:80它根本不知道/api的请求被 Nginx 偷偷转发到了8080。在浏览器眼里一切都是同一个源。 五、补充proxy_set_header那几行到底在干嘛你可能注意到配置里总有这么几行透传头信息的代码很多人直接复制粘贴但不理解它的作用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;指令作用不加会怎样Host $host把原始请求的域名传给后端后端拿到的 Host 可能是localhost:8080而不是用户实际访问的域名X-Real-IP把客户端真实 IP 传给后端后端通过request.getRemoteAddr()拿到的是 Nginx 的 IP127.0.0.1而非用户真实 IPX-Forwarded-For记录整个代理链路的 IP多层代理时无法追溯请求来源X-Forwarded-Proto告诉后端原始请求是 HTTP 还是 HTTPS后端无法正确判断协议可能影响重定向逻辑一句话总结这几行配置确保后端能获取到用户的真实信息而不是 Nginx 代理服务器的信息。生产环境务必加上。✍️ 总结整篇文章的核心其实就一句话Nginx 反向代理 在浏览器和后端服务之间加了一个智能前台统一入口、按路径分发、隐藏内部细节。再回顾一下关键要点listen 80—— 让 Nginx 监听默认端口用户无需输入端口号location /—— 匹配前端静态资源请求location /api/—— 匹配后端 API 请求proxy_pass—— 核心指令实现请求转发try_files—— SPA 单页应用的救命配置保证前端路由正常工作同源效果—— 浏览器只看到80端口跨域问题自然消失