nginx перенаправляет POST-запросы на GET-запросы

У меня есть приложение Rails 4.1, работающее на puma веб-сервере. Я использую nginx в качестве прокси-сервера. Несколько дней назад все работало очень хорошо. Я обновил свое приложение, и внезапно некоторые POST запросы начали перенаправляться на тот же URL-адрес, но как GET запрос. Я пытался откатиться на предыдущие рабочие версии, безуспешно.

Я нашел очень интересное поведение. Я протестировал свой API с помощью curl.

  • Если я сделал POST запрос на URL-адрес http://myapp.com/tasks/easy_task/calculate/, он перенаправляется на тот же URL-адрес, но как запрос GET.
  • Потом сделал POSTзапрос к http://myapp.com/, вернул 404
  • Потом сделал POSTзапрос к http://myapp.com/tasks, вернул 404
  • Потом сделал POSTзапрос к http://myapp.com/tasks/easy_task, вернул 404
  • Затем я сделал POSTзапрос к http://myapp.com/tasks/easy_task/calculate, вернул 200. УРА!

То же самое произошло, когда я использовал приложение Chrome Postman. Сначала он перенаправлялся, но после предыдущих шагов он работает хорошо.

Я использую это приложение в моем другом приложении. Я использую RestClient для выполнения http-запросов. Когда я пытаюсь сделать запрос POST, возникает исключение RestClient::MovedPermanently (301 Moved Permanently).

  • Я переустановил nginx на 1.7.3.
  • Перезапущенный сервер (виртуальная машина)
  • повторно развернул мое приложение, развернул предыдущие версии
  • без успеха :(

Я нашел похожие вопросы в stackoverflow, но ни один из них не дал мне подсказки, как решить эту проблему. Я надеюсь, что вы можете помочь мне решить эту проблему. Заранее спасибо!

Похожие вопросы: - запрос POST превращается в запрос GET - запрос POST таинственным образом превращается в запрос GET

конфиг нгинкс:

$ 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;
}

пума

$ bundle exec puma -d -e production -b unix:///tmp/myapp.com-puma.sock --pidfile /home/projects/mycompany/myapp.com/shared/tmp/pids/puma.pid
$

Пример доступа.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"

person Zhomart    schedule 11.07.2014    source источник
comment
Вероятно, 404, все эти ответы генерируются вашими приложениями rails. Можете ли вы показать nginx error.log?   -  person mr_tron    schedule 11.07.2014
comment
Журнал error.log nginx пуст. Все ошибки 404 являются ошибками приложения rails. Когда 301, приложение rails даже не получает запрос. Я закрыл приложение rails, так или иначе, я получил 301.   -  person Zhomart    schedule 12.07.2014


Ответы (3)


Я нашел решение. Когда я выполнял запрос POST, я использовал URL-адрес, заканчивающийся косой чертой, например http://myapp.com/tasks/easy_task/calculate/.

Когда я использовал URL без косой черты в конце, например http://myapp.com/tasks/easy_task/calculate, все работает отлично!

Я думаю, это из-за этого правила

rewrite ^/(.*)/$ /$1 permanent; # Truncate trailing slashes

Я закрываю этот вопрос. Завтра.

person Zhomart    schedule 11.07.2014
comment
Мое состояние было прямо противоположным, я отправлял сообщения в /tasks, а определение моего местоположения — /tasks/. Благодаря вашей теме здесь, я нашел решение! :) - person Chris.Zou; 19.10.2014

301 — это постоянное перенаправление, а 302 — временное, поэтому поисковые системы не меняют URL-адреса, связанные с этим веб-сайтом, при использовании 302.
Указанный метод и тело 301 и 302 не следует изменять, но не все пользовательские агенты согласуются с этим. Прочитайте это объяснение от Mozilla:

Протокол передачи гипертекста (HTTP) 302 Обнаружен код ответа состояния перенаправления указывает, что запрошенный ресурс был временно перемещен на URL-адрес, указанный в заголовке Location. Браузер перенаправляет на эту страницу, но поисковые системы не обновляют свои ссылки на ресурс (в SEO-говорении говорится, что «ссылочный сок» не пересылается на новый URL). Даже если спецификация требует, чтобы метод (и тело) не изменялись при выполнении перенаправления, не все пользовательские агенты соответствуют этому — вы все равно можете найти этот тип программного обеспечения с ошибками. Поэтому рекомендуется устанавливать код 302 только в качестве ответа на методы GET или HEAD и вместо этого использовать временное перенаправление 307, поскольку в этом случае изменение метода явно запрещено. В тех случаях, когда вы хотите, чтобы используемый метод был изменен на GET, вместо этого используйте 303 See Other. Это полезно, когда вы хотите дать ответ на метод PUT, который не является загруженным ресурсом, а подтверждающим сообщением, например: «вы успешно загрузили XYZ».

308 и 307 постоянно перенаправляют на новый ресурс, но они гарантируют, что тело и метод запроса не будут изменены. разница в том, что 308 является постоянным, а 307 — временным, поэтому 308 будет сигнализировать поисковым системам об изменении URL-адресов. видеть это:

Единственная разница между 307 и 302 заключается в том, что 307 гарантирует, что метод и тело не будут изменены при выполнении перенаправленного запроса. С 302 некоторые старые клиенты неправильно меняли метод на GET: поведение с не-GET-методами и 302 в этом случае непредсказуемо в Интернете, тогда как поведение с 307 предсказуемо. Для запросов GET их поведение идентично.

TL;DR Если вы хотите полностью перенаправить на новый ресурс, а метод и тело запросов не должны изменяться, используйте 308 вместо 301 или 302.

person Miad Abdi    schedule 16.03.2021

В моем случае перенаправление означало, что если я отправляю POST на http://... proxy_pass преобразуется в GET.

Измените URL-адрес на https://..., и он будет передан как POST, как и предполагалось.

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;
}
person Nick T    schedule 11.05.2021