nginx 适配 react-routerbrowserRoute 路由问题
本文环境比较复杂,首先两层 nginx 转发,并且访问路径也不是根路径。加上对 nginx 一知半解,各路搜索一看,全程懵逼。最终没有一个能用的。最后还是靠同事帮助,文档大法结束加班。本文知识点:location 优先级,nginx 资源文件寻找方式,rewrite 重定向问题。
location 优先级
- = 开头表示精确匹配
- ^~ 开头表示 uri 以某个常规字符串开头,理解为匹配 url 路径即可。nginx 不对 url 做编码,因此请求为 /static/20%/aa,可以被规则 ^~ /static/ /aa 匹配到(注意是空格)。以 xx 开头
- ~ 开头表示区分大小写的正则匹配 以 xx 结尾
- ~* 开头表示不区分大小写的正则匹配 以 xx 结尾
- !~ 和!~* 分别为区分大小写不匹配及不区分大小写不匹配 的正则
- / 通用匹配,任何请求都会匹配到。
try_file 使用
当用户请求 http://localhost/example 时,这里的 $uri 就是 /example。
try_files 会到硬盘里尝试找这个文件。如果存在名为 /$root/example(其中 $root 是项目代码安装目录)的文件,就直接把这个文件的内容发送给用户。
显然,目录中没有叫 example 的文件。然后就看 $uri/,增加了一个 /,也就是看有没有名为 /$root/example/ 的目录。
又找不到,就会 fall back 到 try_files 的最后一个选项 /index.php,发起一个内部“子请求”,也就是相当于 nginx 发起一个 HTTP 请求到 http://localhost/index.php。
适配 react-router browserrouter 配置
首先文件存放路径是子目录 /usr/local/services/app_logical_server-1.0/bin/app/screen
访问路径是 https://example.com/app/screen/
错误的 nginx 配置
server {
listen 8080;
root /usr/local/services/app_logical_server-1.0/bin/app/screen;
location ~* \.(gif|jpg|png|js|css)$ {root /usr/local/services/app_logical_server-1.0/bin/app/screen/;}
location ^~ /app/screen {
root html;
index index.html;
try_files $uri $uri/ /index.html;
}
}
错误点
错误现象是 index.html 可以找到,但是 index.html 中的 js 写的是相对路径,导致所有的静态资源文件也进入了第二个 location,导致页面白屏。
分析如下。
1. 优先级问题
首先匹配 =,其次匹配 ^~, 其次是按文件中顺序的正则匹配,最后是交给 / 通用匹配。当有匹配成功时候,停止匹配,按当前匹配规则处理请求。
~* 的优先级低于 ^~ 所以第一个配置静态资源文件虽然写在前面,还是不会进去的。
2. server root 配置错误
解决优先级问题后,问题依然存在。原因就是这个。root 在 server 和 location 中都有,都是配置文件开始寻找的根路径,如果 url 是 https://xxxx:8084/app/screen,location 中的配置优先级高于 server。首先会进入第二个 location 中, 寻找文件,文件路径是 root 和域名后面的路径的拼接,例如:访问路径是 https://example.com/app/screen/umi.js
,server root 为 /usr/local/services/app_logical_server-1.0/bin/app/screen
。nginx 寻找文件的地址为/usr/local/services/app_logical_server-1.0/bin/app/screen/app/screen/umi.js
. 当然找不到,报 404 错误。
正确的配置
server {
listen 8084;
root /usr/local/services/app_logical_server-1.0/bin/;
location ~* \.(gif|jpg|png|js|css)$ {root /usr/local/services/app_logical_server-1.0/bin;}
location ~* /app/screen {
#try_files $uri $uri/ /usr/local/services/app_logical_server-1.0/bin/app/screen/index.html;
root /usr/local/services/app_logical_server-1.0/bin;
try_files /app/screen/index.html =404;
}
}
不带 /
的 url 重定向问题
当前配置还有个问题,就是末尾不带斜杠时,index.html 可以加载到,但是 html 中的资源文件写的相对路径,当 url 为 https://example/app/screen
时,相对路径为 https://example/app
,以 js 为例,https://example/app/umi.js
, 所以报 404 错误。
解决方案为,利用 location 优先级,再加一个 = /app/screen
的 location。
location = /sa/screen {rewrite ^([^.]*[^/])$ $1/ permanent;
port_in_redirect off;
}
但是到此还没结束。因为业务需要,本层 nginx 前面还有一层 Nginx。所以 301 重定向的时候,会带上端口号。导致找不到请求。port_in_redirect off;
配置可以解决此问题
最终版完美配置
server {
listen 8084;
root /usr/local/services/app_logical_server-1.0/bin/;
location = /sa/screen {rewrite ^([^.]*[^/])$ $1/ permanent;
port_in_redirect off;
}
location ~* \.(gif|jpg|png|js|css)$ {root /usr/local/services/app_logical_server-1.0/bin;}
location ~* /app/screen {
#try_files $uri $uri/ /usr/local/services/app_logical_server-1.0/bin/app/screen/index.html;
root /usr/local/services/app_logical_server-1.0/bin;
try_files /app/screen/index.html =404;
}
}