Nginx 部署单页面应用时,访问除了跟路由外的其他路由,提示找不到资源。
SPA 的单个入口
默认情况下,一个打包好的 Vue 应用结构如下:
html
|-- assets
|-- favicon.ico
|-- index.html
这个应用只提供了一个入口文件(index.html
),它在 Nginx 中的 location 块一般长这样:
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
当我们访问该站点的一个资源时,如果访问的是根路径,例如http://127.0.0.1/
,它将匹配上面的/
块,然后 Nginx 去 root 指定的目录下获取资源(根路径对应的资源 URI 是/
),即最终的资源路径为/usr/share/nginx/html/
,这个路径以/
结尾,表明它是一个目录,按照 index 的约定 Nginx 继续查找它下面的index.html
文件或者index.htm
文件,显然最后返回的是/usr/share/nginx/html/index.html
文件。
如果我们访问http://127.0.0.1/favicon.ico
,进入/
块后其 URI 为favicon.ico
,Nginx 会查找 root 下的favicon.ico
文件,显然 Nginx 可以直接找到/usr/share/nginx/html/favicon.ico
文件,所以这个请求也是可以正常完成的。
如果我们访问http://127.0.0.1/test
,进入/
块后其 URI 为test
,Nginx 匹配不到$root/test
文件,于是出现下面的结果:
这种情况在单页面应用中十分常见,这是因为 Nginx 默认只查找文件(URI 不以/
结尾)或者目录(URI 以/
结尾)下的 index 文件。
try_files 的使用例子
try_files指令用在 server 块或者 location 块中,用来指定资源的查找顺序。官方提供了这样一个例子:
location /images/ {
root /images;
try_files $uri $uri/ /images/default.gif;
}
假如我们请求资源http://127.0.0.1/images/test.gif
,在 server 全局块中其 URI 为/images/test.gif
。
如果这个 URI 被/images/
块匹配,在块内部,其 URI 变为test.gif
(去掉公共前缀后剩余部分仍可作为资源的标识符)。
Nginx 按照 try_files 指定的顺序搜索资源:
- 搜索的根目录是 server.root + location.root,例如
/usr/share/nginx/html/images
- 首先搜索
$uri
,即搜索根目录下的test.gif
文件,如果找到了则返回资源 - 然后搜索
$uri/
,即搜索根目录下的test.gif/
子目录下的 index 文件,如果找到了则返回资源 - 最后直接返回
images/default.gif
文件
try_files 的详细用法
官方文档:http://nginx.org/en/docs/http/ngx_http_core_module.html#try_files
用法:
try_files file URI;
try_files file =CODE;
按照 file 指定的顺序检查资源文件是否存在,返回第一个查找到的资源文件。
查找过程只在当前块指定的目录下进行。
指定参数以/
结尾以检查资源目录是否存在,例如$uri/
。
如果所有 file 都没有匹配上,try_files 的最后一个参数将作为兜底选项,它可以是:
- 用于重定向的一个 URI:Nginx 将会查找另一个资源
- 一个错误代码:Nginx 直接返回该代码对应的页面,例如 404
- 一个代理服务器……
- ……
解决方案
在/
块中配置 try_files 即可:
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
评论区