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

Posted

技术标签:

【中文标题】如何使用 nginx 通过 proxy_pass 转发查询字符串参数?【英文标题】:How can query string parameters be forwarded through a proxy_pass with nginx? 【发布时间】:2011-12-29 03:55:37 【问题描述】:
upstream apache 
   server 127.0.0.1:8080;

server
   location ~* ^/service/(.*)$ 
      proxy_pass http://apache/$1;
      proxy_redirect off;
   
 

上面的sn-p会将url包含字符串“service”的请求重定向到另一个服务器,但不包含查询参数。

【问题讨论】:

【参考方案1】:

添加了 $request_uri: proxy_pass http://apache/$request_uri;

【讨论】:

【参考方案2】:

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

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

使用查询字符串:

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

【讨论】:

nginx 文档明确指出尽可能避免使用if。在这种情况下,使用location 的解决方案可能是正确的,如另一个答案所示。 不管怎样,再一个解决方案,即使它有缺点更好【参考方案3】:

github 要点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$tokenk1=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

【讨论】:

【参考方案4】:

来自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/;

或者,如果您想使用正则表达式位置,只需包含参数:

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

【讨论】:

我不相信你能做到后者。我试过了,nginx 向我抱怨。 如何投诉?我刚刚在 nginx 1.3.4 上对其进行了测试,对我来说效果很好。 嗯..我现在不记得了:(但我觉得它可能与“〜*”有关。但是,我刚刚检查过,我有nginx 1.2.3(通过自制)。也许就是这样? “proxy_redirect default”不能与带有变量的“proxy_pass”指令一起使用 必须使用重写location /service/ rewrite ^\/service\/(.*) /$1 break; proxy_pass http://apache; 【参考方案5】:

您必须使用 rewrite 来使用 proxy_pass 传递参数 这是我为 angularjs 应用程序部署到 s3 所做的示例

S3 Static Website Hosting Route All Paths to 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;

【讨论】:

这看起来可以很好地处理路径参数 (/path/params) 但不能很好地处理查询参数 (?query=params)? 啊不,我错了,应该自动添加查询参数(它们在我的测试中)。【参考方案6】:

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

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

带参数

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

【讨论】:

请记住,这将使服务器在重定向之前向客户端返回 301 响应。上面的proxy_pass 指令在服务器端进行重定向。 如果您的查询参数包含 URL(%) 编码字符,这将中断。请改用安德鲁的答案。 这个答案与反向代理无关。例如,如果 service_url 不能直接从 Internet 访问(这很可能在反向代理场景中),它将完全失败。此外,它告诉客户端它下次应该直接使用重定向 URL(301 永久移动),这在这种情况下也可能不需要。【参考方案7】:

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

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

【讨论】:

以上是关于如何使用 nginx 通过 proxy_pass 转发查询字符串参数?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 nginx proxy_pass 保留请求 url

如何解决 Nginx “proxy_pass 502 Bad Gateway”错误

Nginx proxy_pass使用$host变量

nginx proxy_pass基于请求方法是POST,PUT还是DELETE

Nginx学习-实例:location+proxy_pass配置中左斜杠彻底弄清

nginx反向代理location和proxy_pass的映射关系