我有一个Web应用程序想要在没有启用CORS的情况下从第三方站点访问文件。请求可以是具有任意参数的任意域。我向我的域发送请求,其中包含编码为GET参数的目标,即
GET https://www.example.com/proxy/?url=http%3A%2F%2Fnginx.org%2Fen%2Fdocs%2Fhttp%2Fngx_http_proxy_module.html
然后在Nginx中我做了
location /proxy/ {
resolver 8.8.8.8;
set_unescape_uri $dst $arg_url;
proxy_pass $dst;
}
这适用于单个文件,但目标服务器有时会返回一个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;
但这不起作用。我还尝试保存Location标头,然后用
忽略传入的标头proxy_hide_header
并将其替换为我自己的
proxy_set_header
但忽略会导致我丢失保存它的变量。
如何配置Nginx以完成重定向的处理,以便在代理站点重定向时,我可以传递编码的URL将返回给用户?
答案 0 :(得分:4)
您的不成功方法存在一些问题:
proxy_set_header
设置前往上游服务器的标头,而不是客户端。因此,即使$sent_http_location
没有为空,您的配置也无法按照您的意愿运行。
$sent_http_<header>
变量指向与将发送到客户端的响应头相同的内存区域。因此,当proxy_hide_header
生效时,指定的标头将与相应的$sent_http_<header>
的值一起从内存中删除。
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;
}
请注意使用$upstream_http_location
代替$sent_http_location
。当Nginx离开该位置的上下文时,它假定该请求将被代理到另一个上游,或者以其他方式处理,因此它清除从上一个proxy_pass
收到的标头,以便为新响应腾出空间头。
与表示将发送给客户端的响应头的$sent_http_<header>
vairables不同,$upstream_http_<header>
变量表示从上游收到的响应头。因此,当请求被代理到另一个上游服务器时,它们仅被替换为新值。因此,一旦设置,这些变量可以随时使用,它们不会被清除。