如何使用nginx通过proxy_pass转发查询字符串参数?


114
upstream apache {
   server 127.0.0.1:8080;
}
server{
   location ~* ^/service/(.*)$ {
      proxy_pass http://apache/$1;
      proxy_redirect off;
   }
 }

上面的代码段会将URL包含字符串“ service”的请求重定向到另一台服务器,但不包括查询参数。

Answers:


163

proxy_pass文档中:

一种特殊情况是在proxy_pass语句中使用变量:不使用请求的URL,您有责任自己构造目标URL。

由于您在目标中使用$ 1,因此nginx依靠您准确地告诉它要传递什么。您可以通过两种方式解决此问题。首先,使用proxy_pass剥离uri的开头很简单:

location /service/ {
  # Note the trailing slash on the proxy_pass.
  # It tells nginx to replace /service/ with / when passing the request.
  proxy_pass http://apache/;
}

或者,如果您想使用正则表达式位置,只需添加args:

location ~* ^/service/(.*) {
  proxy_pass http://apache/$1$is_args$args;
}

1
我不相信您可以做到。我尝试了,nginx向我抱怨。
duma 2012年

3
抱怨如何?我刚刚在nginx 1.3.4上进行了测试,对我来说效果很好。
kolbyjack 2012年

赫姆..我现在不能回忆:(但我觉得它可能已经涉及到了“〜*”不过,我刚才检查,我有nginx的1.2.3(通过自制),也许这就是它。?
duma 2012年

“ proxy_redirect default”可能无法与带有变量的“ proxy_pass”指令一起使用
Jean-Philippe Caruana 2013年

1
必须使用重写 location /service/ { rewrite ^\/service\/(.*) /$1 break; proxy_pass http://apache; }
Andrew Arnautov

27

我使用的是kolbyjack第二种方法的稍微修改后的版本,~而不是~*

location ~ ^/service/ {
  proxy_pass http://apache/$uri$is_args$args;
}

10

我修改了@kolbyjack代码以使其适用

http://website1/service
http://website1/service/

带参数

location ~ ^/service/?(.*) {
    return 301 http://service_url/$1$is_args$args;
}

1
请记住,这将使服务器在重定向之前向客户端返回301响应。proxy_pass上面的指令在服务器端执行重定向。
卢克·彼得森

1
如果您的查询参数包含URL(%)编码的字符,这将中断。请改用安德鲁的答案。
David Weber

9

您必须使用重写以使用proxy_pass传递参数,这是我将angularjs应用部署到s3的示例

S3静态网站托管将所有路径路由到Index.html

适应您的需求将类似于

location /service/ {
    rewrite ^\/service\/(.*) /$1 break;
    proxy_pass http://apache;
}

如果您想以http://127.0.0.1:8080/query/params/结尾

如果您想以http://127.0.0.1:8080/service/query/params/结尾,则 需要类似

location /service/ {
    rewrite ^\/(.*) /$1 break;
    proxy_pass http://apache;
}

1
看起来它可以很好地处理路径参数(/path/params),但不能很好地处理查询参数(?query=params)?
威尔

啊,不,我的错,查询参数应该自动添加(它们在我的测试中)。
威尔

2

github gist https://gist.github.com/anjia0532/da4a17f848468de5a374c860b17607e7

#set $token "?"; # deprecated

set $token ""; # declar token is ""(empty str) for original request without args,because $is_args concat any var will be `?`

if ($is_args) { # if the request has args update token to "&"
    set $token "&";
}

location /test {
    set $args "${args}${token}k1=v1&k2=v2"; # update original append custom params with $token
    # if no args $is_args is empty str,else it's "?"
    # http is scheme
    # service is upstream server
    #proxy_pass http://service/$uri$is_args$args; # deprecated remove `/`
    proxy_pass http://service$uri$is_args$args; # proxy pass
}

#http://localhost/test?foo=bar ==> http://service/test?foo=bar&k1=v1&k2=v2

#http://localhost/test/ ==> http://service/test?k1=v1&k2=v2

1

要在没有查询字符串的情况下进行重定向,请在侦听端口行下的服务器块中添加以下行:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/;
}

使用查询字符串:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/?$query_string;
}

1
Nginx文档是明确的,避免if在可能的情况下使用。在这种情况下,使用location其他答案所示的解决方案可能是正确的。
安德烈斯·莫拉莱斯

2
无论如何,即使有缺点也有更好的解决方法
Dmitry Malugin

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.