16

Is it possible/how can I configure an Nginx location block to proxy to different backends depending on the request method (ie. GET/POST)?

The reason is, I am currently handling the 2 methods at 2 different URLs (one via http proxy and the other via fcgi) and am trying to make it more "REST"ful so, would ideally like the GETting the resource to return the list, while POSTing to the same resource should add to the list.

25

I don't use this configuration, but based on the examples here:

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

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

If your writing your own application, you can also consider checking GET/POST in it, and sending X-Accel-Redirect headers to hand off transport of the files to nginx.

  • The GET block is a proxy_pass in my case, but otherwise that works. At the moment I'm not using the second if block, nginx appears to be stopping "processing" when the fastcgi_pass directive is reached (ie. not falling through and running the proxy pass as well) because I want anything other than POST to revert to the proxy. – Brenton Alker Jun 20 '10 at 11:51
  • 1
    Note that if is generally discouraged by the Nginx documentation: nginx.com/resources/wiki/start/topics/depth/ifisevil – vog Dec 28 '16 at 17:07
  • 1
    So, what is the alternative? – W.M. Sep 13 '17 at 9:51
  • 1
    @W.M. See my answer: serverfault.com/a/823053/175421 – vog Dec 14 '17 at 8:45
  • @vog, Interesting. Pretty smart way to do it. Thanks for sharing. – W.M. Dec 14 '17 at 12:53
21

Although you could achieve this with if, this is generally discouraged by the Nginx documentation, because if doesn't play well with other directives. For example, assume that GET should be open for everyone, while POST is only for authenticated users, using HTTP Basic Auth. That would require if to be combined with auth_basic, which doesn't work properly.

Here is an alternative that works without if. The trick is to use "GET" and "POST" as part of the upstream names, so these can be addressed by variable substitution:

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

To combine this with HTTP Basic Auth for everything but GET, just add a limit_except block:

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

This is what i did to make things working for me

add_header Allow "GET, POST, HEAD" always;
if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
    proxy_pass http://back-end;
}
  • Hoe exactly does that switch between two endpoints based on request method? – Basic Feb 10 at 14:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.