Lecture05-Nginx-动静分离配置

文章目录

    [toc]

    单词词性音标含义
    staticadj./ˈstætɪk/静态的(图片、CSS、JS 等不变资源)
    dynamicadj./daɪˈnæmɪk/动态的(需要后端实时生成的请求)
    locationn./ləʊˈkeɪʃn/匹配规则(按路径/类型区分请求去向)
    rootn./ruːt/根目录(静态文件的磁盘位置)
    try_filesn./traɪ faɪlz/依次尝试文件(找不到回退到 index.html)

    Lecture05-Nginx-动静分离配置

    1、本节讲什么

    把静态资源(图片、CSS、JS)交给 Nginx 直接返回(快、不占后端),把动态请求(/api)转发给后端。这就是动静分离,也是前后端分离项目最常见的 Nginx 配置。

    2、概念速览

    什么是动静分离:请求来了先分一分——静态的 Nginx 自己给,动态的转后端。

    请求 ─→ Nginx ─┬─ 静态资源(.js/.css/图片) → Nginx 直接从磁盘返回(不走后端)
                    └─ 动态请求(/api)          → 转发给后端服务器
    

    类比(Java):像"CDN / 静态资源服务器 + 应用服务器"分工——静态不进 Tomcat/SpringBoot,动态才进,后端压力小很多。

    关键:靠 location 按路径/文件类型区分。静态用 root/alias 指到磁盘目录,动态用 proxy_pass 转后端。

    3、照着做

    ① 准备静态目录(放前端打包产物,如 dist)

    sudo mkdir -p /var/www/flower-front
    # 把前端构建产物(npm run build 后的 dist 内容)拷进去
    sudo cp -r /path/to/dist/* /var/www/flower-front/
    

    ② 在站点配置里写动静分离

    server {
        listen 80;
    
        # —— 静态:前端页面 + 资源,Nginx 直接返回 ——
        location / {
            root  /var/www/flower-front;      # 静态文件根目录
            index index.html;
            try_files $uri $uri/ /index.html; # 前端路由刷新时回退到 index.html
        }
    
        # —— 动态:/api 开头的请求转后端 ——
        location /api/ {
            proxy_pass http://flower_backend;      # 后端组(主题 4 配的)
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
    

    说明:proxy_pass http://flower_backend;(不带末尾 /)会把 /api/xxx 原样转发给后端;若写成 proxy_pass http://flower_backend; 且后端接口是 /api/xxx,路径就一致。具体以你后端接口前缀为准(可参考前端教程第 23/27 节的 /api 约定)。

    关于 try_files:为什么前端 SPA 刷新要回退到 index.html

    try_files $uri $uri/ /index.html; 是 Vue/React 单页应用(SPA)部署的灵魂配置,三个参数按顺序找文件:

    顺序参数找什么例子(请求 /logo.png)
    ①$uri找同名文件/var/www/flower-front/logo.png → 找到,直接返回
    ②$uri/找同名目录/var/www/flower-front/about/ 里的 index.html
    ③/index.html前面都没找到,兜底返回这个返回 SPA 入口

    为什么需要第三个参数?

    Vue/React 的路由是"假路由"——/user、/order、/about 这些路径都是前端 JS 用 History API 模拟的,服务器上根本不存在这些文件。

    场景:用户在 /about 页面按 F5 刷新
    
    没有 try_files:
      浏览器 → Nginx:我要 /about
      Nginx:磁盘上找 about 文件 → 不存在 → 404 ❌
    
    有 try_files:
      浏览器 → Nginx:我要 /about
      Nginx:① 找 about 文件 → 没有
            ② 找 about/ 目录 → 没有
            ③ 兜底返回 /index.html
      浏览器加载 index.html → Vue Router 读 URL 是 /about → Vue 自己执行路由操作 → 显示"关于我们" ✅
    
    请求磁盘上有没有没有 try_files有 try_files
    /logo.png有直接返回图片直接返回(①命中)
    /css/app.css有直接返回直接返回(①命中)
    /about(SPA 路由)没有404返回 index.html,前端接管(③兜底)
    /order/123(SPA 路由)没有404返回 index.html,前端接管(③兜底)

    一句话:静态资源(js/css/png)真存在,直接返回;前端路由(/about、/order)假存在,兜底回 index.html 让前端路由去处理。

    这就是为什么部署 Vue 项目到 Nginx 后,从首页点进子页面一切正常,但直接刷新子页面就 404——99% 就是漏了这行 try_files。

    ③ 测试并重载

    sudo nginx -t
    sudo systemctl reload nginx
    

    ④ 验证

    curl http://localhost/                 # 返回前端 index.html(静态)
    curl http://localhost/assets/app.js    # 返回静态 JS(Nginx 直接给,不转后端)
    curl http://localhost/api/flowers      # 返回后端数据(动态,转后端)
    

    看 Nginx 日志能区分:静态请求由 worker 直接响应,动态请求走了后端。

    4、常见疑问

    • Q:root 和 alias 有啥区别? A:root 会把匹配的路径拼在 root 后面找文件(root /var/www; location /a/ → 找 /var/www/a/x);alias 是直接替换(alias /var/www/a; location /a/ → 找 /var/www/a/x)。静态文件多用 root,初学者先记住 root 就行。

    • Q:/var/www 这个目录对 Nginx 有什么特殊?必须放这吗? A:没有任何特殊性,Nginx 对目录位置零要求,root 指到哪它读哪。用 /var/www 只是约定俗成——从 Apache 时代就这么放,Ubuntu 装完 Nginx 默认站点也在 /var/www/html,大家跟着抄。实际放 /opt/xxx、/data/xxx 都行:

      误区正解
      Nginx 只认 /var/wwwNginx 对目录位置零要求,root 指到哪读哪
      必须放 /var/www只是"大家都这么干",不是"Nginx 必须这么干"

      只要满足两个条件:① 路径写对;② Nginx worker 进程(www-data 用户)对该目录有读权限。如果你非要放别处,给权限就行:

      sudo chown -R www-data:www-data /opt/flower-front
      

      真正"特殊"的不是目录,是权限——放 /var/www 默认权限刚好允许 www-data 读,放自己家目录就会 403。

    • Q:前端是 Vue 单页应用,刷新 /flowers 404 怎么办? A:就是上面那行 try_files $uri $uri/ /index.html; 解决的(详见上面"关于 try_files"展开说明)。

    • Q:图片请求也走后端怎么办? A:说明没命中静态 location。确认路径是否匹配 location /(或专门的 location ~* \.(png|jpg|js|css)$),并把文件放对 root 目录。



    5、本节验证

    • 理解动静分离的思想(静态自己给、动态转后端)✅
    • 会配静态 root + try_files 与动态 proxy_pass ✅
    • 会用 curl 分别验证静态与动态请求 ✅
    end