【问题标题】:How to forward the URL's all parameters through a proxy_pass with nginx?如何使用 nginx 通过 proxy_pass 转发 URL 的所有参数?
【发布时间】:2021-08-08 07:38:42
【问题描述】:

如何通过 nginx 的 proxy_pass 转发 URL 的所有参数?

Nginx 配置:

location /proxy/ {
     if ($request_method = HEAD) { return 200; }

     if ( $arg_address != "" ) {
      proxy_pass $arg_address;
      return 301 $arg_address;
      }  

     proxy_ssl_verify       off;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header X-Real-IP $remote_addr;
 }

这个网址有效:

https://localhost/proxy/?address=https://exemple.com/transfer/file.txt ==>> https://exemple.com/transfer/file.txt

https://localhost/proxy/?address=https://exemple.com/transfer/file.txt?host-id=1 ==>> https://exemple.com/transfer/file.tx?host-id=1

如果我添加多个参数,它会被截断为第一个“&”

https://localhost/proxy/?address=https://exemple.com/transfer/file.txt?host-id=1&password=123456&date=xxxxxx ==>> https://exemple.com/transfer/file.txt?host-id=1

如何转移整个网址?

【问题讨论】:

    标签: nginx parameters nginx-config proxypass


    【解决方案1】:

    在我们得到答案之前,我想问一下你想要实现什么?您要代理请求还是生成 HTTP 301 重定向?具有以下构造

    if ( $arg_address != "" ) {
        proxy_pass $arg_address;
        return 301 $arg_address;
    }  
    

    你总是会得到一个重定向,因为来自ngx_http_rewrite_module 的指令在任何其他指令之前执行,所以proxy_pass 指令在这里是没用的。 ngx_http_rewrite_module 非常特别,与大多数其他模块不同。尽管 nginx 配置通常是声明性的,但 rewrite 模块强制评估其指令。这对于每个 nginx 新手来说总是一个困惑的根源。你可以阅读更多关于重写模块内部实现here

    如果您想代理请求而不是生成重定向,则需要删除 return 并将 resolver 指令添加到您的配置中。 Here 你可以阅读为什么需要它。

    “肮脏的黑客”解决方案

    话虽如此,回到问题上来。当然,当nginx收到请求时

    https://localhost/proxy/?address=https://example.com/transfer/file.txt?host-id=1&password=123456&date=20210520
    

    arg_NAME 变量将按以下方式填充:

    arg_address => https://example.com/transfer/file.txt?host-id=1
    arg_password => 123456
    arg_date => 20210520
    

    这是正确的预期行为。

    您可以做些什么来保留所有其他查询参数?最简单的是假设address 之后的所有查询参数都被传递到上游并使用map 指令来获取所需的字符串:

    map $args $address {
        ~(?:^|&)(address=.*)    $1;
    }
    
    server {
        ...
        location /proxy/ {
            ...
            if ($address) {
                # 'proxy_pass $address' or 'return 301 $address' here
            }  
            ...
        }
        ...
    }
    

    只有在address 查询参数后面有问号,否则只有$arg_address 值时,我们才会在哪里获取查询字符串的其余部分:

    map $args $address {
        ~(?:^|&)(address=[^&?]+\?.*)    $1;
        default                         $arg_address;
    }
    

    可靠的解决方案

    虽然上面的答案通常是可行的,但我宁愿尝试在 address 查询参数上使用 URL encoding 来设计我的代理解决方案,以避免将 reserved characters 用作查询参数值的一部分。上面的 URL 编码请求看起来像

    https://localhost/proxy/?address=https%3A%2F%2Fexample.com%2Ftransfer%2Ffile.txt%3Fhost-id%3D1%26password%3D123456%26date%3D20210520
    

    不好的是,“vanilla” nginx 没有能力对任意字符串进行 URL 解码。但是可以使用OpenResty/lua-nginx-module

    location /proxy/ {
        ...
        set_by_lua_block $address { return ngx.unescape_uri(ngx.var.arg_address) }
        if ($address) {
            # 'proxy_pass $address' or 'return 301 $address' here
        }  
        ...
    }
    

    set-misc-nginx-module:

    location /proxy/ {
        ...
        if ($arg_address) {
            set_unescape_uri $address $arg_address;
            # 'proxy_pass $address' or 'return 301 $address' here
        }  
        ...
    }
    

    也许使用njs也可以做到这一点,但我没有使用它,无法给你举个例子。

    【讨论】:

      猜你喜欢
      • 2011-12-29
      • 1970-01-01
      • 2018-10-19
      • 1970-01-01
      • 1970-01-01
      • 2019-03-14
      • 2011-08-15
      • 2015-03-16
      • 2023-03-12
      相关资源
      最近更新 更多