Nginx代理的请求方法


17

是否可以/如何配置Nginx位置块以根据请求方法(即GET / POST)代理到不同的后端?

原因是,我目前正在2个不同的URL处处理2个方法(一个通过http代理,另一个通过fcgi),并试图使其更加“ REST”有效,因此,理想情况下,希望获取资源以返回列表,而在发布到相同资源时应添加到列表中。

Answers:


27

我不使用此配置,但是基于此处示例

location /service  {
  if ($request_method = POST ) {
    fastcgi_pass 127.0.0.1:1234;
  }

  if ($request_method = GET ) {
     alias /path/to/files;
  }
}

如果您编写自己的应用程序,则还可以考虑检查其中的GET / POST,并发送X-Accel-Redirect标头以将文件传输到nginx。


在我的情况下,GET块是proxy_pass,但是否则可以正常工作。目前,我不使用第二个if块,当到达fastcgi_pass指令时(即不掉线也不运行代理传递),nginx 似乎正在停止“处理”,因为我想要除POST以外的任何东西给代理。
布伦顿·阿尔克

2
请注意,ifNginx文档通常不建议这样做:nginx.com/resources/wiki/start/topics/depth/ifisevil
vog

1
那么,替代品是什么?
WM

1
@WM看到我的答案:serverfault.com/a/823053/175421
vog

@vog,有趣。相当聪明的方式来做到这一点。感谢分享。
WM

23

尽管您可以使用实现此功能if但是Nginx文档通常不建议if这样做,因为它不能与其他指令一起使用。例如,假设GET应该对所有人开放,而POST仅对使用HTTP Basic Auth的经过身份验证的用户开放。那将需要if与结合使用auth_basic,但无法正常工作。

这是一种不带的替代方法if。诀窍是使用“ GET”和“ POST”作为上游名称的一部分,因此可以通过变量替换来解决:

http {
  upstream other_GET {
    server ...;
  }
  upstream other_POST {
    server ...;
  }
  server {
    location /service {
      proxy_pass http://other_$request_method;
    }
  }
}

要将其与HTTP Basic Auth结合使用,除了GET以外的所有内容,只需添加一个代码limit_except块:

  ...
    location /service {
      proxy_pass http://other_$request_method;
      limit_except GET {
        auth_basic ...;
      }
    }
  ...

这种方法的问题502 gateway error在于,由于no resolver defined to resolve other_HEAD(或任何上游缺失),我们现在将返回。返回类似的东西会更加语义化405 method not allowed。有没有办法做到这一点?
詹姆斯

1
@詹姆斯:这个灵魂也许是一个新问题,指的是这个问题。我没有这个细节的答案,但也许其他人也没有答案。
vog

0

这就是我所做的,使事情对我有用

add_header Allow "GET, POST, HEAD" always;
if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
    proxy_pass http://back-end;
}

e头究竟是根据请求方法在两个端点之间切换的?
基本

0

略微更改vog的答案,以包括其他方法(如OPTIONS,PUT等)的默认处理程序。

    upstream webdav_default {
            server example.com;
    }
    upstream webdav_upload {
            server example.com:8081;
    }
    upstream webdav_download {
            server example.com:8082;
    }
    server {
            map upstream_location $request_method {
                    GET     webdav_download;
                    HEAD    webdav_download;
                    PUT     webdav_upload;
                    LOCK    webdav_upload;
                    default webdav_default;
            }
            location / {
                    proxy_pass https://$upstream_location;
            }
    }

0

我无法从@timmmmmy得到答案,但它为我指出了地图文档,这对我有用:

map $request_method $upstream_location {
   PUT     example.com:8081;
   POST    example.com:8081;
   PATCH   example.com:8081;
   default example.com:8082;
}
server {
   location / {
      proxy_pass https://$upstream_location;
   }
}
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.