nginx как обрабатывать POST-запросы в обработчике 404?

Вопрос или проблема

в моем /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 и испытывает аналогичную проблему, важно следовать следующим шагам:

  1. Использование именованных блоков: Замена директивы error_page на использование именованных блоков обрабатывает запросы более гибко. Это дает контроль над всеми характеристиками запроса, включая метод, заголовки и тело.

  2. Конфигурация try_files: Директива try_files может быть мощным инструментом для проверки существования файла и выполнения внутреннего перенаправления без смены метода запроса или потери данных.

  3. Проверка на стороне PHP: В PHP убедитесь, что ваш код правильно обрабатывает любые методы HTTP, и используйте супер глобальные массивы, такие как $_POST и $_SERVER, чтобы гарантировать правильное распознавание метода запроса и его данных.

  4. Отладка через логирование: Включите логирование запросов на стороне Nginx, чтобы отследить, как запросы обрабатываются сервером. Это поможет вам выявить, где и почему запросы теряют свои атрибуты.

Это решение демонстрирует важность понимания точного поведения различных технологий, которые вы используете в своем стеке, и умения гибко адаптировать конфигурации для достижения желаемого результата. В контексте вашего вопроса Nginx позволяет изящно обойти стандартную проблему с потерей данных POST при использовании традиционной директивы error_page, что начинает открывать возможности для более сложных обработок и логики на стороне сервера без изменения архитектуры приложения.

Оцените материал
Добавить комментарий

Капча загружается...