Вопрос или проблема
в моем /etc/nginx/sites-enabled/devdb.easy-ads.com
у меня есть:
server {
root /srv/http/devdb.easy-ads.com/www;
index index.html index.htm index.nginx-debian.html index.php;
server_name devdb.easy-ads.com;
location / {
# Сначала пытаемся обработать запрос как файл, затем
# как директорию, затем возвращаем 404.
try_files $uri $uri/ =404;
}
# передача PHP-скриптов на сервер FastCGI
#
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
}
error_page 404 = /index.php;
listen [::]:443 ssl ipv6only=on; # управляется Certbot
listen 443 ssl; # управляется Certbot
ssl_certificate /etc/letsencrypt/live/devdb.easy-ads.com/fullchain.pem; # управляется Certbot
ssl_certificate_key /etc/letsencrypt/live/devdb.easy-ads.com/privkey.pem; # управляется Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # управляется Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # управляется Certbot
}
и это работает нормально для uri, не вызывающих 404, так же как и для GET-запросов, независимо от того, вызывают они 404 или нет, но все 404 POST-запросы конвертируются в GET-запросы перед отправкой в index.php, как я могу это остановить? в php, $_POST
это пустой массив, даже когда это не должно быть так, а $_SERVER['REQUEST_METHOD']
ошибочно содержит GET
…
… по какой-то неизвестной причине,
error_page 404 = /index.php;
заставляет все запросы становиться GET-запросами, но изменив это на
error_page 404 = @the404block;
location @the404block {
try_files $uri $uri/ /index.php$is_args$args;
}
исправляет проблему.
Это потому, что дизайнеры nginx выпили слишком много водки во время проектирования nginx.
Не водку. Радиоактивные огурцы.
if (!-e $request_filename) {
rewrite ^/(.*) /404.php?$query_string;
}
.
Ответ или решение
Вопрос о том, как обработать POST-запросы в Nginx при возникновении ошибки 404, требует детального рассмотрения специфики работы сервера и его конфигурации. Разберем эту ситуацию с использованием подхода TEA (Теория, Пример, Применение).
Теория
Nginx имеет встроенную систему обработки ошибок, которая позволяет перенаправлять запросы на определенные URI при возникновении непредвиденных ошибок, таких как 404 – не найдено. Однако при перенаправлении запросов на другой URI посредством директивы error_page
, Nginx преобразует все методы HTTP-запросов в GET. Это поведение связано с тем, что перенаправление запрашивает страницу по новому URI, и, следовательно, метод запроса по умолчанию становится GET.
Это означает, что когда POST-запрос на несуществующий ресурс попадает в обработчик 404, он теряет свое состояние, а именно тело запроса POST и заголовки, превращаясь в GET. Следовательно, в PHP массив $_POST
оказывается пустым, а $_SERVER['REQUEST_METHOD']
содержит GET.
Пример
В приведенной вами конфигурации Nginx, проблема возникает именно из-за использования директивы:
error_page 404 = /index.php;
Данный код превращает любые 404 POST-запросы в GET-запросы, теряя данные POST и искажая метод запроса.
Решение
Ваше решение с использованием именованного блока улучшает ситуацию:
error_page 404 = @the404block;
location @the404block {
try_files $uri $uri/ /index.php$is_args$args;
}
Использование директивы try_files
в сочетании с именованным блоком location
позволяет сохранять исходный метод запроса, так как такой подход не предполагает прямого перенаправления запроса в другой URI.
Применение
Для тех, кто настраивает Nginx и испытывает аналогичную проблему, важно следовать следующим шагам:
-
Использование именованных блоков: Замена директивы
error_page
на использование именованных блоков обрабатывает запросы более гибко. Это дает контроль над всеми характеристиками запроса, включая метод, заголовки и тело. -
Конфигурация try_files: Директива
try_files
может быть мощным инструментом для проверки существования файла и выполнения внутреннего перенаправления без смены метода запроса или потери данных. -
Проверка на стороне PHP: В PHP убедитесь, что ваш код правильно обрабатывает любые методы HTTP, и используйте супер глобальные массивы, такие как
$_POST
и$_SERVER
, чтобы гарантировать правильное распознавание метода запроса и его данных. -
Отладка через логирование: Включите логирование запросов на стороне Nginx, чтобы отследить, как запросы обрабатываются сервером. Это поможет вам выявить, где и почему запросы теряют свои атрибуты.
Это решение демонстрирует важность понимания точного поведения различных технологий, которые вы используете в своем стеке, и умения гибко адаптировать конфигурации для достижения желаемого результата. В контексте вашего вопроса Nginx позволяет изящно обойти стандартную проблему с потерей данных POST при использовании традиционной директивы error_page
, что начинает открывать возможности для более сложных обработок и логики на стороне сервера без изменения архитектуры приложения.