Appearance
为什么配了 try_files 后,静态资源和 JS 还能正常拿到
更新: 6/28/2026 字数: 0 字 时长: 0 分钟
配 try_files $uri $uri/ /index.html 这种 SPA 兜底规则后,很多人担心所有请求都被重写到 index.html,导致 JS、CSS、图片拿不到。实际不会。原因在于 try_files 是按顺序逐个尝试,命中即停——只要磁盘上真有这个文件,它在第一步就被返回了,根本走不到最后的兜底。下面拆开讲。
一、try_files 的执行顺序规则

try_files 的语法是:
nginx
try_files file1 file2 ... uri_or_=code;它的核心规则是:从左到右依次检查每个参数对应的文件/目录在磁盘上是否存在,遇到第一个存在的就立即用它响应并停止后续检查;前面全部不存在时,才使用最后一个参数作为兜底。
以最典型的前端配置为例:
nginx
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}它的尝试顺序是:
$uri:把请求路径拼到root后面,检查这个文件是否存在。比如请求/static/app.js,就检查/usr/share/nginx/html/static/app.js在不在。$uri/:如果上一步的文件不存在,检查它作为目录是否存在(目录存在则按index指令找首页)。/index.html:前两步都没命中时,才回退到这个兜底文件,把 SPA 的入口页面返回给浏览器,由前端路由接管。
关键点有两个:
- 最后一个参数是"兜底",不是"总是执行"。它只在前面所有真实文件都查不到时才生效。
- 顺序不可颠倒。真实存在的文件优先级最高,永远排在兜底之前被命中。
二、静态资源 / JS 为什么能被正常命中

理解了顺序规则,结论就很自然了:JS、CSS、图片这些资源是真实存在于磁盘上的文件,它们在 try_files 的第一步 $uri 就被命中并返回了,根本到不了 /index.html 这一步。
具体分两种请求看:
1)静态资源请求(真实文件存在)
浏览器请求 /static/js/app.4f2a.js。Nginx 执行 try_files:
- 第一步检查
$uri→/usr/share/nginx/html/static/js/app.4f2a.js,文件存在 → 直接返回这个 JS 文件,附带正确的Content-Type: application/javascript,流程结束。
兜底的 /index.html 压根没机会执行。CSS、图片、字体同理——只要构建产物确实放在了 root 目录下对应路径,第一步必然命中。
2)前端路由请求(无对应真实文件)
浏览器请求 /user/profile(这是 SPA 的前端路由,磁盘上并没有这么个文件或目录)。Nginx 执行 try_files:
- 第一步
$uri→/user/profile文件不存在; - 第二步
$uri/→/user/profile/目录也不存在; - 第三步兜底 → 返回
/index.html,浏览器加载到 SPA 入口,再由前端路由(如 React Router、Vue Router)根据地址栏渲染对应页面。
底层逻辑一句话概括:try_files 用"磁盘上文件是否真实存在"作为分流开关。存在的(静态资源)走第一步原样返回,不存在的(前端虚拟路由)才走兜底。两类请求天然被区分开,互不干扰。
三、需要留意的两个细节
虽然机制本身没问题,但实践中有两点容易踩坑,值得提一句:
root/alias路径要配对。try_files的$uri是相对于location里的root(或alias)去磁盘上找文件的。如果root指错了目录,第一步查不到真实文件,JS 就会被错误地回退成index.html——表现为"请求 JS 却返回了一段 HTML",浏览器报Unexpected token '<'。遇到这种报错,先查root路径对不对。可以为静态资源单独开
location提升效率。很多团队会把静态资源单独匹配出来,跳过兜底逻辑、顺便加上缓存头:
nginx
# 静态资源:长缓存,不走 SPA 兜底
location /static/ {
root /usr/share/nginx/html;
expires 1y;
add_header Cache-Control "public, immutable";
}
# 其余路径:SPA 兜底
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}这样静态资源走专属 location,前端路由走兜底 location,职责更清晰,缓存策略也好控制。