Why is nginx changing HTTP method on rewrite rule?

marcosbeirigo asked:

Whenever I receive a request on mydomain.com, I redirect it to the www subdomain using the following rewrite rule:

server_name mydomain.com;
rewrite ^(.*)$ $scheme://www.mydomain.com$1 permanent;

But if a POST request is received, it is redirected as GET.
Why? What’s the proper way to redirect this?

My answer:

It’s happening because the web browser is changing the POST request to a GET request.

According to RFC 2616, the browser is not supposed to change the request method when a 301 is received, but instead warn the user and ask for confirmation to resubmit the request to the new URL. Unfortunately I have never seen a web browser actually do this. But the reason for doing either of these is to protect the user against various hijacking scenarios.

See section 10.3.2:

If the 301 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.

Note: When automatically redirecting a POST request after receiving a 301 status code, some existing HTTP/1.0 user agents will erroneously change it into a GET request.

The quick and easy fix is to fix your web application so that it stops serving URLs that need to be redirected. This will also improve your site’s overall performance and SEO ranking. For instance, if you redirect example.com to www.example.com then all of the URLs served by your web application should start with www.example.com.

View the full question and answer on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.