nginx: 当 proxy_pass 失败时回退到 try_files 需要不寻常的配置。

7

我正在使用Nginx来提供单页面应用。基本上,我们只需要在找不到匹配文件时提供index.html页面。该位置如下所示,并且一直正常工作:

location / {
   try_files $uri $uri/ /index.html
}

现在我想查询一个上游服务器,只有在它失败时才使用上述try_files指令。
如果try_files被移动到备用位置,例如:
location @fallback {
  try_files $uri $uri/ /index.html;
}

location / {
  proxy_pass http://127.0.0.1:8080;
  proxy_intercept_errors on;
  error_page 400 403 502 503 504 @fallback;
}

如果上游服务器不可用,客户端将看到Nginx 502错误页面,而不是从文件系统提供的文件。

最后我找到了一个解决方案,通过在/index.html备用中使用双斜杠来实现。这是整个配置文件,可以与官方的nginx docker镜像一起使用进行测试。

events {
} 

http {

  error_log /var/log/nginx/error.log;
  access_log /var/log/nginx/access.log;

  server {

    listen 80;

    root /usr/share/nginx/html/;

    location / { 
      proxy_pass http://127.0.0.1:9990;
      proxy_intercept_errors on; 
      error_page 400 403 502 503 504 = @fallback;
    }

    location @fallback {
      try_files $uri?$args /index.html //index.html;
    }
  }
}

可以通过类似命令的方式运行

docker run -v /path/to/www/folder:/usr/share/nginx/html:ro -v /path/to/config/nginx.conf:/etc/nginx/nginx.conf -d -p 8080:80 nginx

如果在最后一个index.html回退之前没有出现双斜杠,就会发生如下情况。
location @fallback {
  try_files $uri?$args /index.html;
}

当请求一个非根URL时,nginx会在文件系统上构造一个路径,如<root>index.html,其中缺少正确的分隔符<root>/index.html

最后一个问题:为什么这个设置要求在try_files指令中使用双斜杠?为什么不能直接使用常规配置中的try_files部分并将其移动到拦截错误时使用的回退位置?


可能反过来行吗?在404时回退到proxy_pass?我遇到了类似的问题,希望能有一个比较优雅的解决方案 :) - Félix Adriyel Gagnon-Grenier
不,这个顺序有很好的理由:proxy_pass在服务器端呈现网页并在浏览器中重新注入到SPA中,而fallback只是提供了SPA,然后需要从API加载当前页面的数据,这会导致更长的加载时间等问题。 - st-h
我明白了。这将是一个适合添加到问题中的细节,因为它改变了范围! - Félix Adriyel Gagnon-Grenier
1个回答

3

我曾遇到类似的情况,解决方法是采用这个页面常见陷阱中提供的建议,即先提供静态文件,然后再使用代理。

location / {
    try_files $uri $uri/ @proxy;
}
location @proxy {
    proxy_pass http://127.0.0.1:9990;
}

在这种情况下,首先会在根目录中查找文件是否存在作为静态文件,然后将请求代理到 http://127.0.0.1:9000。这在功能上是等效的,除非您希望代理的文件覆盖静态文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接