【问题标题】:How to get nginx to do a redirect to url-encoded query parameter如何让 nginx 重定向到 url 编码的查询参数
【发布时间】:2021-04-26 10:35:42
【问题描述】:

我需要对通过查询参数传递的 url 进行代理调用,例如: 我的 nginx 代理部署在:https://myproxy.net

如果重定向参数不是 url 编码的,我可以使用这个块进行调用:

  location /basepath {
        if ( $arg_redirect = '') { 
          return 400 "Missing redirect directive in request"; 
        }
        proxy_pass $arg_redirect;
        proxy_intercept_errors on;
        error_page 301 302 307 = @handle_redirects;
    }

错误拦截和@handle_redirects 然后处理可能在新目的地弹出的其他 30X 代码。
这适用于请求:
GET: https://myproxy.net/basepath?redirect=https://destination.com/somepath/uuid

我需要做什么才能使其工作:
GET:https://myproxy.net/basepath?redirect=https%3A%2F%2Fdestination.com%2Fsomepath%2Fuuid

此外,作为规范的一部分,它必须是纯 nginx,而不是附加模块、lua 等。 谢谢!

【问题讨论】:

    标签: nginx nginx-reverse-proxy nginx-location


    【解决方案1】:

    好的,有一个非常奇怪和好奇的解决方案

    server {
      listen 80;
      resolver x.x.x.x;
      location /basepath {
        if ($arg_redirect = '') {
          return 400 "Missing redirect directive in request";
        }
        proxy_pass http://127.0.0.1:80/basepath/$arg_redirect;
      }
      location ~ ^/basepath/(?<proto>\w+):/(?<redir>.+)$ {
        proxy_pass $proto://$redir;
      }
    }
    

    Nginx 不会使用 proxy_pass 中的变量对路径进行编码并按原样发送。所以,我将 $arg_* 作为 proxy_pass uri 的一部分,向 self 发送请求,nginx 将收到新的请求,该请求将被解码。

    但是因为 Nginx 会清理路径并将 // 替换为 / 我在正则表达式中拆分协议部分。

    而且...我绝不会推荐使用此解决方案,但它确实有效 :)

    【讨论】:

      【解决方案2】:

      其实proxy_pass默认是做规范化的,但是只影响$uri部分。因此,您只需要解码传递的字符串的开头即可使其正常工作:

        location / {
          if ( $arg_redirect = '') {
            return 400 "Missing redirect directive in request";
          }
          if ( $arg_redirect ~ (.+)%3A%2F%2F(.+) ){ # fix :// between scheme and destination
            set $arg_redirect $1://$2;
          }
          if ( $arg_redirect ~ (.+?)%3A(.*) ){ # fix : between destination and port
            set $arg_redirect $1:$2;
          }
          if ( $arg_redirect ~ (.+?)%2F(.*) ){ # fix / after port, the rest will be decoded by proxy_pass
            set $arg_redirect $1/$2;
          }
          proxy_pass $arg_redirect;
        }
      

      通过上面我设法访问http://localhost/?redirect=http%3A%2F%2F127.0.0.1%3A81%2Fsfoo%20something%2Fs

      解决方案似乎很脏,使用默认模块的唯一替代方法是map(在我看来甚至更不干净)。我宁愿将redirect 参数拆分为多个部分:方案(http 或 https)、目标、端口和 uri。这样你就可以在不重写的情况下构造完整的地址:

      proxy_pass $arg_scheme://$arg_dest:$arg_port/$arg_uri
      

      【讨论】:

      • 感谢替换示例。将 url 分割成段的想法很简单,我真的应该想到,绝对是迄今为止最干净的解决方案!
      【解决方案3】:

      试试这样,如果有效,请告诉我

        location /basepath {
              if ( $arg_redirect = '') { 
                return 400 "Missing redirect directive in request"; 
              }
      
              set_unescape_uri $decodedredirect $arg_redirect;
      
              proxy_pass $decodedredirect;
              proxy_intercept_errors on;
              error_page 301 302 307 = @handle_redirects;
          }
      

      【讨论】:

      • 感谢您的想法,但 set_???? 指令是 set-misc-nginx-module 的一部分
      • 我很抱歉我错过了“纯 nginx,而不是附加模块”
      猜你喜欢
      • 2015-01-20
      • 2021-07-22
      • 1970-01-01
      • 2014-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-06
      相关资源
      最近更新 更多