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

时间:2016-11-26 10:38:15

标签: redirect nginx proxy cors

我有一个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将返回给用户?

1 个答案:

答案 0 :(得分:4)

您的不成功方法存在一些问题:

  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,结果也总是空变量。

  4. 最后一个问题是最严重的问题。在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>变量表示从上游收到的响应头。因此,当请求被代理到另一个上游服务器时,它们仅被替换为新值。因此,一旦设置,这些变量可以随时使用,它们不会被清除。