Nginx反向代理自定义Location无法加载静态资源问题求助
Nginx反向代理自定义Location无法加载静态资源问题求助
兄弟,我看了你遇到的问题——在同一个子域名下用/test/路径反向代理到另一个容器,但静态资源全是404,这个坑我之前也踩过,咱们来一步步捋清楚问题出在哪,以及怎么解决。
首先分析下你当前的情况:
- 你设置了
location /test/来代理到另一个容器的4123端口,但浏览器请求https://foo.bar.baz/test/styles.css时返回404,核心原因有两个可能:- 路径匹配问题:你的
location /test/是带结尾斜杠的,Nginx只会匹配以/test/开头的路径(比如/test/xxx),但/test/styles.css并不符合这个规则,会被转到根路径的location /里,而根路径指向的是主站点容器,自然找不到这个资源。 - 后端URI不匹配:就算路径匹配上了,后端容器的资源是放在根路径下的(比如
http://dockercontainer:4123/styles.css),但当前请求传递给后端的是/test/styles.css,后端找不到这个路径的资源,也会返回404。
- 路径匹配问题:你的
接下来给你两个针对性的解决方案,你可以根据实际情况选:
方案一:重写URI,让后端收到根路径请求
这个方法是在代理时把/test/前缀去掉,让后端容器收到的是它期望的根路径请求。修改你的location /test/配置如下:
location ^~ /test/ { proxy_set_header Host $host; proxy_set_header X-Forwarded-Scheme $scheme; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Real-IP $remote_addr; # 关键:把/test/开头的路径重写为去掉前缀的格式 rewrite ^/test/(.*)$ /$1 break; # 这里注意!你当前写的proxy_pass是http://foo.bar.baz:4123/,应该换成Docker容器的内部地址 # 比如http://your-another-container:4123/,不然可能会触发循环代理 proxy_pass http://your-another-container:4123/; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; proxy_http_version 1.1; }
解释下:
^~ /test/是强制匹配这个路径,避免被其他正则location抢占;rewrite规则把/test/styles.css转换成/styles.css后再传递给后端,这样后端就能找到对应的静态资源了。
方案二:修改页面内的资源路径(适合后端无法修改的场景)
如果后端网站生成的资源是绝对路径(比如<link href="/styles.css">),浏览器会自动拼成https://foo.bar.baz/styles.css,这时候就算用了方案一,这个请求还是会走到根路径的location /。这时候可以用Nginx的sub_filter模块来替换页面里的资源链接,让它们都加上/test/前缀:
location ^~ /test/ { proxy_set_header Host $host; proxy_set_header X-Forwarded-Scheme $scheme; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Real-IP $remote_addr; proxy_pass http://your-another-container:4123/; # 替换页面中所有绝对路径的资源链接,加上/test/前缀 sub_filter 'href="/' 'href="/test/'; sub_filter 'src="/' 'src="/test/'; # 开启全局替换,不然只替换第一个匹配项 sub_filter_once off; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; proxy_http_version 1.1; }
这个方法会在返回给浏览器的页面里,把所有以/开头的资源链接替换成/test/开头,这样浏览器就会请求https://foo.bar.baz/test/styles.css,而这个路径会被你的location /test/捕获并正确代理到后端。
最后提醒你一下:一定要把proxy_pass里的http://foo.bar.baz:4123/换成Docker容器的内部名称或者IP,比如你那个容器叫test-container,就写成http://test-container:4123/,不然Nginx会去请求外部域名,可能导致循环代理或者无法访问的问题。
备注:内容来源于stack exchange,提问作者Shadark
相关产品推荐
相关产品推荐

