Nginx 代理拦截重定向并将自定义重定向传递给客户端

Flo*_*obe 2 proxy redirect nginx

我有一个 Web 应用程序想要在未启用 CORS 的情况下从第三方站点访问文件。请求可以是具有任意参数的任意域。我正在向我的域发送一个请求,其中包含编码为 GET 参数的目标,即

GET https://www.example.com/proxy/?url=http%3A%2F%2Fnginx.org%2Fen%2Fdocs%2Fhttp%2Fngx_http_proxy_module.html
Run Code Online (Sandbox Code Playgroud)

然后在 Nginx 中我做

location /proxy/ {
    resolver 8.8.8.8;
    set_unescape_uri $dst $arg_url;
    proxy_pass $dst;
}
Run Code Online (Sandbox Code Playgroud)

这适用于单个文件,但目标服务器有时会返回一个 Location 标头,我想拦截并修改该标头以便客户端重试。

基本上我想转义 $sent_http_location,将其附加到https://www.example.com/proxy/?url=并将其传递回浏览器以重试。

我试过做

set_escape_uri $tmp $sent_http_location;
proxy_redirect $sent_http_header /pass/?v=$tmp;
Run Code Online (Sandbox Code Playgroud)

但这行不通。我还尝试保存 Location 标头,然后忽略传入的标头

proxy_hide_header
Run Code Online (Sandbox Code Playgroud)

并用我自己的替换它

proxy_set_header
Run Code Online (Sandbox Code Playgroud)

但忽略会导致我丢失保存它的变量。

如何配置 Nginx 来完成重定向处理,以便在代理站点重定向时将编码的 URL 返回给用户?

Iva*_*lev 5

您的不成功方法存在几个问题:

  1. proxy_set_header设置发送到上游服务器而不是客户端的标头。因此,即使$sent_http_location不为空,您的配置也不可能按您希望的方式工作。

  2. $sent_http_<header>变量指向与将发送到客户端的响应标头完全相同的内存区域。因此,当proxy_hide_header生效时,指定的标头以及相应的值将从内存中删除$sent_http_<header>

  3. set_escape_uri在请求处理的早期阶段工作,proxy_pass调用之前的方式并Location从上游服务器返回标头。所以它总是会处理当时的空变量$sent_http_location,结果也总是空变量。

最后一个问题是最严重的。set_escape_uri之后唯一的方法proxy_pass是强制 Nginx 离开当前位置并重新开始处理。这可以通过以下技巧来完成error_page

location /proxy/ {
    resolver 8.8.8.8;
    set_unescape_uri $dst $arg_url;
    proxy_pass $dst;

    proxy_intercept_errors on;
    error_page 301 = @rewrite_301;
}

location @rewrite_301 {
    set_escape_uri $location $upstream_http_location;
    return 301 /pass/?v=$location;
}
Run Code Online (Sandbox Code Playgroud)

请注意使用$upstream_http_location代替$sent_http_location。当 Nginx 离开该位置的上下文时,它假设请求将被代理到另一个上游,或以其他方式处理,因此它会清除从最后收到的标头,proxy_pass为新的响应标头腾出空间。

$sent_http_<header>与代表将发送到客户端的响应标头的变量不同,$upstream_http_<header>变量代表从上游接收的响应标头。因此,只有当请求代理到另一个上游服务器时,它们才会被新值替换。因此,一旦设置,这些变量就可以随时使用,并且不会被清除。