Skip to content

006. Nginx 静态资源与反向代理

学习目标

这一节重点理解 Nginx 如何同时服务前端页面、静态资源和后端接口。

学完后,你应该能理解:

  • 静态资源目录是什么;
  • 为什么前端打包产物可以直接由 Nginx 托管;
  • 单页面应用刷新后为什么可能 404;
  • locationaliastry_files 分别解决什么问题;
  • 为什么要把后端 API 代理到统一入口;
  • 如何减少生产环境跨域问题。

静态资源目录

宝塔创建站点后,会生成一个网站根目录。

这个目录可以理解成:

所有静态资源放置的目录。

只要把文件放进这个目录,浏览器就可以通过 HTTP 访问到。

例如目录里有:

txt
1.txt

访问:

txt
http://服务器IP/1.txt

就能拿到这个文件内容。

HTTP 默认端口是 80,所以:

txt
http://服务器IP

实际访问的是服务器的 80 端口。

前端打包产物也是静态资源

React / Vue 前端打包后,产物通常是:

  • index.html
  • JS 文件;
  • CSS 文件;
  • 图片;
  • 字体;
  • 其他静态资源。

这些文件本身不需要 Node 服务才能运行。只要 Nginx 能把它们返回给浏览器,浏览器就能加载并执行前端应用。

所以前端部署可以理解成:

  1. 本地执行 build;
  2. 得到 dist 或类似目录;
  3. 上传到服务器站点目录;
  4. Nginx 托管这些静态文件。

访问目录时会找 index.html

当访问一个目录路径时,Nginx 会尝试找这个目录下的入口文件。

例如访问:

txt
http://服务器IP/ai-admin/

Nginx 会尝试返回:

txt
/ai-admin/index.html

这就是为什么前端打包目录里必须有 index.html

单页面应用刷新 404

React / Vue 单页面应用的路由很多时候不是服务器真实文件。

例如页面里跳转到:

txt
/ai-admin/pages/user

这个地址在前端路由里存在,但服务器目录里未必真的有:

txt
/ai-admin/pages/user/index.html

如果直接刷新浏览器,Nginx 会按真实文件路径去找,找不到就可能 404。

这不是前端页面坏了,而是单页面应用需要服务器把未知路由回退到 index.html

location 是一次匹配规则

Nginx 里的 location 可以理解成“当请求路径匹配某个前缀时,按这段规则处理”。

例如:

nginx
location /ai-admin/ {
  alias /www/wwwroot/web/ai-admin/;
  try_files $uri $uri/ /ai-admin/index.html;
}

这里表达的是:

  • 请求以 /ai-admin/ 开头;
  • 实际去服务器目录 /www/wwwroot/web/ai-admin/ 找文件;
  • 如果真实文件不存在,就回退到 /ai-admin/index.html

alias 是路径别名

alias 用来把 URL 路径映射到服务器文件目录。

浏览器访问:

txt
/ai-admin/assets/index.css

Nginx 可以去真实目录里找:

txt
/www/wwwroot/web/ai-admin/assets/index.css

这就是 URL 路径和服务器文件路径之间的转换。

try_files 解决前端刷新问题

try_files 的核心作用是:按顺序尝试找文件。

例如:

nginx
try_files $uri $uri/ /ai-admin/index.html;

可以理解成:

  1. 先找请求路径对应的文件;
  2. 再找请求路径对应的目录;
  3. 都没有,就返回前端入口 index.html

这样刷新一个前端路由时,Nginx 不会直接报 404,而是把请求交给前端应用,由 React Router 或 Vue Router 决定显示哪个页面。

静态文件访问

除了前端页面,系统还会有上传文件,例如发票图片。

这些文件也可以先放在服务器目录里,由 Nginx 暴露访问路径。

例如:

txt
/upload/file/xxx.png

对应服务器某个上传目录下的图片。

学习阶段先直接托管这些文件。更复杂的权限控制,例如签名 URL、对象存储权限、私有文件访问,后面再深入。

直接访问根路径

如果前端必须访问:

txt
http://服务器IP/ai-admin/

分享给别人时不够友好。

可以在 Nginx 里把根路径重定向到前端入口:

txt
/ -> /ai-admin/

这样别人只访问:

txt
http://服务器IP

也能进入前端页面。

代理后端 API

如果前端走 80 端口,后端直接暴露 7003 端口,浏览器会认为它们不是同源。

更好的方式是让前端请求:

txt
/api

再由 Nginx 转发到后端真实端口:

txt
/api -> http://127.0.0.1:7003

这样浏览器看到的仍然是同一个协议、同一个 IP 或域名、同一个端口。

WebSocket 也需要代理

后续实时语音识别会用到 WebSocket。

WebSocket 和普通 HTTP 请求不完全一样,Nginx 代理时要额外处理连接升级相关请求头。

当前先记住:如果一个功能需要实时通信,比如语音识别流式返回、实时消息推送,就不能只按普通 HTTP 请求理解。

前端生产环境 API 地址

前端本地开发时,可能会直接请求:

txt
http://服务器IP:7003

生产构建时,要改成走统一路径,例如:

txt
/api

然后重新 build,再上传新的打包产物。

这样部署后的请求路径就会变成:

txt
http://服务器IP/api/xxx

浏览器看到的是同源请求,跨域问题自然减少。

生产环境跨域策略

当 Nginx 已经统一了前端、后端和静态资源入口后,后端就不应该继续无条件允许所有跨域。

可以按环境区分:

环境跨域策略
本地开发可以适当放开,方便调试
测试环境限制到测试前端地址
生产环境尽量同源访问,只允许必要来源

部署不是只让页面能打开,还要让访问方式接近真实企业项目。

多环境代理

同一台服务器上可能同时有开发环境和测试环境。

它们后端端口不能相同,例如:

txt
开发后端:7003
测试后端:7004

可以用 Nginx 路径区分:

txt
/dev-api  -> 7003
/test-api -> 7004

也可以用不同域名区分。当前学习阶段先掌握同一个 IP 下按路径代理的方式。

AI Agent 课程学习文档。