如何通过Nginx强制使用相对URI解决静态站点资源加载问题
当然可以!不用修改站点里的任何链接,只需要调整Nginx配置就能搞定这个问题。下面给你几个实用的方案,按需选择:
方案一:用try_files统一处理资源请求
这是最通用的方案,适合大多数场景,尤其是你的站点是单页应用的情况。修改配置如下:
# 先处理根路径的资源请求,自动映射到/cool目录下 location / { # 先尝试加载当前路径的资源,如果不存在,就去/cool目录找,最后返回index.html(适配单页路由) try_files $uri /cool$uri /cool/index.html; } location /cool { alias /var/www/cool/build; index index.html; }
原理:当浏览器请求mydomain.com/styles.css时,Nginx会先检查服务器根目录下有没有这个文件(一般没有),然后自动尝试/cool/styles.css,也就是对应到/var/www/cool/build/styles.css,完美匹配你的资源文件。同时,访问/cool路径时依然正常返回页面,单页应用的路由也能被/cool/index.html正确处理。
方案二:用rewrite规则重写资源路径
如果你不想让根路径的其他请求被干扰,可以用更精准的rewrite规则,只针对站点的资源文件进行路径重写:
location /cool { alias /var/www/cool/build; index index.html; } # 匹配所有以/开头的资源目录(比如/css/、/js/、/images/下的文件) location ~ ^/(css|js|images)/.*$ { rewrite ^/(.*)$ /cool/$1 last; } # 单独匹配根路径下的单个资源文件(比如/styles.css、/app.js) location ~ ^/[^/]+.(css|js|png|jpg|svg)$ { rewrite ^/(.*)$ /cool/$1 last; }
原理:通过正则匹配所有静态资源请求,把路径里的/xxx重写成/cool/xxx,让Nginx去对应的目录找资源。这种方式更精准,不会影响根路径下的其他站点或服务。
方案三:用sub_filter修改HTML中的资源路径
如果你的Nginx启用了ngx_http_sub_module模块(大部分发行版默认启用),可以自动修改返回的HTML内容,把绝对路径的前缀/替换成/cool/:
location /cool { alias /var/www/cool/build; index index.html; # 开启sub_filter,替换HTML里的绝对路径 sub_filter 'href="/' 'href="/cool/'; sub_filter 'src="/' 'src="/cool/'; sub_filter_once off; # 替换所有匹配项,而不仅仅是第一个 }
原理:当Nginx返回index.html时,自动把里面的href="/styles.css"改成href="/cool/styles.css",src="/js/app.js"改成src="/cool/js/app.js",这样浏览器就会请求正确的路径了。这种方式不需要处理根路径的请求,但依赖Nginx的sub模块。
注意事项
- 方案一的
try_files会让根路径下的所有未匹配请求都指向/cool的资源,如果你根路径还有其他站点,建议用方案二或三。 - 方案三的
sub_filter需要确保HTML里的资源路径是用双引号包裹的,如果是单引号,要修改匹配规则为sub_filter 'href=\'/'' 'href=\'/cool/'';(注意转义)。
内容的提问来源于stack exchange,提问作者Jazcash

