nginx 实现 404 动态备用页面需用 error_page + 命名 location 结合 try_files 或 map 变量做路径决策,保留原始状态码,避免干扰 spa 路由,并确保 fallback 页面大于 512 字节且资源路径正确。

要让 Nginx 在 404 时动态选择备用静态页面,关键不是“重定向”(301/302),而是用 error_page + try_files 或命名 location 实现内部路径匹配与降级 fallback,同时保留原始状态码或按需改写。
用 error_page 触发命名 location 做路径决策
直接写 error_page 404 /fallback.html 是静态映射,无法动态响应不同路径。真正“弹性”的做法是把 404 拦截到一个命名 location,在里面根据请求 URI、变量或文件存在性做判断:
- 先声明拦截:
error_page 404 = @dynamic_fallback;(=表示不改变状态码) - 在
location @dynamic_fallback { }中用try_files尝试多个备选路径,例如:try_files /static/fallback/$uri.html /static/fallback/404-generic.html =404; - 支持变量拼接:如
/static/fallback/$host-$uri.html,实现按域名或路径前缀分级降级 - 加
internal;防止用户直接访问该 location
结合 root 与 alias 实现多级静态降级目录
降级页面不能全堆在一个文件里,应按业务逻辑分层存放。比如按产品线、环境、终端类型准备不同 fallback:
- 设定统一 root:
root /var/www/app; - 在命名 location 中按条件选择 alias 路径:
if ($http_user_agent ~* "Mobile") { set $fallback_dir "/mobile"; }<br>if ($host = "beta.example.com") { set $fallback_dir "/beta"; }<br>alias /var/www/app$fallback_dir/404.html; - 注意:
alias在 if 块中受限,更稳妥方式是用map提前定义变量,再在 location 中引用
确保真实 404 才触发,避免干扰前端路由
尤其在 Vue/React 等 SPA 场景下,不能让所有未命中都进 error_page,否则会吞掉本该由 index.html 处理的合法前端路由:
- 先用
try_files匹配静态资源:try_files $uri $uri/ @router; - 只对明确无扩展名、且非 API 路径才 fallback 到 index.html:
location @router { rewrite ^(.*)$ /index.html last; } - 真正缺失的静态资源(如
/img/logo.png)才会走到 Nginx 默认 404,这时error_page才生效 - 可加日志验证:
log_format debug '$uri → $status';,确认哪些请求真进了 error_page
返回友好页但保持 404 状态码(SEO 友好)
搜索引擎需要知道这是错误页,所以多数情况不该改成 200。正确做法是返回自定义 HTML 同时维持状态码:
- 配置
error_page 404 /static/404.html; - 配套
location = /static/404.html { internal; },防止绕过 - 确保该 HTML 文件大于 512 字节(IE 兼容要求),且引用的 CSS/JS 使用绝对路径或根相对路径(如
/css/app.css) - 若需注入当前请求路径供前端展示,可用 Nginx 变量生成内联脚本:
add_header X-Request-Path "$request_uri" always;,前端 JS 读取 header 或用 SSI











