nginx redirects POST requests to GET request
Solution 1
I've found solution. When I did POST
request, I used url which ends with slash, like http://myapp.com/tasks/easy_task/calculate/
When I used url without slash in the end, like http://myapp.com/tasks/easy_task/calculate
everything works perfectly!
I think it is because of this rule
rewrite ^/(.*)/$ /$1 permanent; # Truncate trailing slashes
I am closing this issue. Tomorrow.
Solution 2
TL;DR If you want to completely redirect to a new resource and method and body of the requests should not be changed use 308 instead of 301 or 302.
301 is permanent redirect but 302 is temporary so search engines don't change urls associated with that website when 302 is used.
301 and 302 indicated method and body should not be altered, but not all user agents align with that. Read this explanation from Mozilla:
The HyperText Transfer Protocol (HTTP) 302 Found redirect status response code indicates that the resource requested has been temporarily moved to the URL given by the Location header. A browser redirects to this page but search engines don't update their links to the resource (in 'SEO-speak', it is said that the 'link-juice' is not sent to the new URL). Even if the specification requires the method (and the body) not to be altered when the redirection is performed, not all user-agents conform here - you can still find this type of bugged software out there. It is therefore recommended to set the 302 code only as a response for GET or HEAD methods and to use 307 Temporary Redirect instead, as the method change is explicitly prohibited in that case. In the cases where you want the method used to be changed to GET, use 303 See Other instead. This is useful when you want to give a response to a PUT method that is not the uploaded resource but a confirmation message such as: 'you successfully uploaded XYZ'.
308 and 307 both permanently redirect to a new resource but they guarantee body and method of request won't be altered. the difference is that 308 is permanent and 307 is temporary, so 308 will signal search engines to change urls. see this:
The only difference between 307 and 302 is that 307 guarantees that the method and the body will not be changed when the redirected request is made. With 302, some old clients were incorrectly changing the method to GET: the behavior with non-GET methods and 302 is then unpredictable on the Web, whereas the behavior with 307 is predictable. For GET requests, their behavior is identical.
Solution 3
In my case, the redirect meant if I POST to http://... the proxy_pass is converted to a GET.
Change the URL to an https://... and it is passed on as a POST as intended.
location /dc1 {
proxy_pass http://localhost:8000;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host www.example.com;
}
Comments
-
Zhomart almost 2 years
I have Rails 4.1 application with runs on
puma
web server. I use nginx as a proxy server. Several days ago everything worked very well. I updated my application, and suddenly somePOST
requests started to redirected to same url but asGET
request. I've tried rollback to previous working versions, no success.I found very interesting behaviour. I tested my API with
curl
.- If I did
POST
request to the urlhttp://myapp.com/tasks/easy_task/calculate/
it redirects to same url but asGET
request. - Then I did
POST
request tohttp://myapp.com/
, returned 404 - Then I did
POST
request tohttp://myapp.com/tasks
, returned 404 - Then I did
POST
request tohttp://myapp.com/tasks/easy_task
, returned 404 - Then I did
POST
request tohttp://myapp.com/tasks/easy_task/calculate
, returned 200. YAY!
Same thing happened when I used chrome's app
Postman
. First it redirected, but after previous steps it works well.I use this app in my other application. I use
RestClient
to make http requests. When I try to makePOST
request it raises an exceptionRestClient::MovedPermanently (301 Moved Permanently)
.- I reinstalled
nginx
to1.7.3
. - Restarted server (virtual machine)
- re deployed my app, deployed previous versions
- no success :(
I found similar questions on stackoverflow, but non of them gave me clue to fix this issue. I hope you can help me to solve this problem. Thanks in advance!
Similar questions: - POST request turns into GET request - POST request mysteriously turn into GET request
nginx config:
$ cat /etc/nginx/sites-enabled/myapp.com.conf # The file generated by Chef for mycompany upstream myapp_mycompany_com { server unix:/tmp/myapp.com-puma.sock; } server { server_name myapp.com; listen 80; access_log /var/log/nginx/myapp.com-access.log; error_log /var/log/nginx/myapp.com-error.log; root /home/projects/mycompany/myapp.com/current/public; gzip on; gzip_types text/plain text/xml application/xml application/xml+rss text/css text/javascript application/javascript application/json; error_page 551 =503 @maintenance; location @maintenance { rewrite ^(.*)$ /system/maintenance.html break; } set $maintenance 0; if (-f $document_root/system/maintenance.html) { set $maintenance 1; } if ($request_uri = /favicon.ico) { # Browsers will try to get favicon if it's not returned with 200ok status set $maintenance 0; } if ($maintenance) { # There can be several reasons for 503 error. We custom return 551 error # to ensure maintenance.html is only shown when it's really maintenance return 551; } rewrite ^/(.*)/$ /$1 permanent; # Truncate trailing slashes try_files $uri @rails; expires -1; location = /favicon.ico { try_files $uri =204; access_log off; log_not_found off; } location @rails { proxy_pass http://myapp_mycompany_com; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $http_host; proxy_redirect off; proxy_intercept_errors on; expires -1; } error_page 500 502 503 504 /500.html; error_page 403 /403.html; error_page 404 /404.html; client_max_body_size 50M; keepalive_timeout 10; }
Puma
$ bundle exec puma -d -e production -b unix:///tmp/myapp.com-puma.sock --pidfile /home/projects/mycompany/myapp.com/shared/tmp/pids/puma.pid $
Example of access.log
123.123.123.123 - - [11/Jul/2014:05:44:17 +0000] "POST /tasks/easy_task/calculate/ HTTP/1.1" 301 184 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2073.0 Safari/537.36" 123.123.123.123 - - [11/Jul/2014:05:44:17 +0000] "GET /tasks/easy_task/calculate HTTP/1.1" 404 713 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2073.0 Safari/537.36" ... 123.123.123.123 - - [11/Jul/2014:06:04:17 +0000] "POST / HTTP/1.1" 404 713 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2073.0 Safari/537.36" 123.123.123.123 - - [11/Jul/2014:06:04:26 +0000] "POST /tasks HTTP/1.1" 404 713 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2073.0 Safari/537.36" 123.123.123.123 - - [11/Jul/2014:06:04:36 +0000] "POST /tasks/easy_task HTTP/1.1" 404 713 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2073.0 Safari/537.36" 123.123.123.123 - - [11/Jul/2014:06:04:42 +0000] "POST /tasks/easy_task/calculate HTTP/1.1" 200 104 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2073.0 Safari/537.36"
- If I did
-
Chris.Zou over 9 yearsMy condition was just the opposite, I was posting to /tasks and my location definition is /tasks/. Thanks to your topic here, I found the solution! :)
-
Ollie Beumkes over 2 yearsSurely this would assume the person changing http to https would have SSL enabled? Interesting point though, may be worth enabling SSL and seeing if the issue goes away!