Назад | Перейти на главную страницу

nginx try_files обрабатывается дважды и завершается ошибкой, если задана ошибка

У меня есть настройка блока местоположения, чтобы перехватывать все запросы файлов и отправлять их PHP-FPM:

location  / {
    try_files  $uri /routing.php?$args;
    fastcgi_pass   unix:/opt/local/var/run/php54/php-fpm-www.sock;
    include       /documents/projects/intahwebz/intahwebz/conf/fastcgi.conf;
}

Это работает и правильно передает запрос на PHP-FPM либо к точному существующему файлу php, который был запрошен, либо с routing.php установить как запускаемый сценарий.

Я попытался добавить страницу с ошибкой, чтобы, если файл маршрутизации когда-либо был удален или недоступен по другим причинам, отображалась страница с ошибкой, а не страница с ошибкой по умолчанию Nginx:

location  / {
    try_files $uri /routing.php?$args /50x_static.html;
    fastcgi_pass   unix:/opt/local/var/run/php54/php-fpm-www.sock;
    include       /documents/projects/intahwebz/intahwebz/conf/fastcgi.conf;
}

Это останавливает routing.php файл не обслуживается, и вместо него отображается страница 50x_static.html. Запросы к существующему файлу PHP по-прежнему работают, т.е. переходят по URL-адресу /dynamic.php

Я понимаю, что последний параметр в try_files команда немного волшебная:

Если файл не найден, выполняется внутреннее перенаправление на последний параметр. Обратите внимание, что только последний параметр вызывает внутреннее перенаправление, предыдущие просто устанавливают внутренний указатель URI. Последний параметр - резервный URI и должен существует, иначе возникнет внутренняя ошибка.

Изучая, почему error_page нарушила конфигурацию, я понял, что для конфигурации, которая работает (без страницы статической ошибки), Nginx действительно дважды соответствует запросу согласно журналу перезаписи Nginx при попытке получить корневой URL "/ ":

"^/proxy/(\d+)/(\w+)/(.+)\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)$" does not match "/", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/proxy/(\d+)/(.+)\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)$" does not match "/", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/staticImage/(\w+)/(.+)\.([^\.]*)$" does not match "/", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/proxy/(\d+)/(\w+)/(.+)\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)$" does not match "/routing.php", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/proxy/(\d+)/(.+)\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)$" does not match "/routing.php", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/staticImage/(\w+)/(.+)\.([^\.]*)$" does not match "/routing.php", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"

т.е. запрос поступает как /, то try_files не обслуживает файл и поэтому перезаписывает запрос из / к /routing.php а затем повторно обрабатывает запрос.

Почему файлы try не обслуживают routing.php файл на первом проходе? Он существует и доступен, иначе его бы не обслужили во второй раз.

РЕДАКТИРОВАТЬ

Удален несвязанный конфиг.

В процитированной вами документации прямо говорится, что «выполняется внутреннее перенаправление на последний параметр». Внутреннее перенаправление обрабатывается так же, как и исходный запрос от клиента - это включает обработку rewrite операторы на уровне сервера, которые вы видите в журнале. Однако если какой-либо другой try_files за исключением того, что последний соответствует существующему файлу, запрос обрабатывается с использованием location конфигурация, где try_files оператор находится, и второго совпадения не будет.

Что касается ваших правил, вы пытались просто опустить $args в try_files?

location  / {
    try_files $uri /routing.php /50x_static.html;
    fastcgi_pass   unix:/opt/local/var/run/php54/php-fpm-www.sock;
    include       /documents/projects/intahwebz/intahwebz/conf/fastcgi.conf;
}

Обратите внимание, что $uri не содержит $args слишком; параметры запроса по-прежнему будут передаваться в бэкэнд FastCGI через QUERY_STRING параметр, который предположительно установлен в вашем fastcgi.conf:

fastcgi_param QUERY_STRING    $query_string;

И если ни то, ни другое $uri ни /routing.php присутствуют в виде файлов, запрос будет перенаправлен на /50x_static.html и обрабатывается в соответствии с location = /50x_static.html в вашей конфигурации (но вторая итерация попыток перезаписи все равно будет выполнена, потому что ваши правила перезаписи размещены на уровне сервера).

Одна очень подозрительная деталь вашей конфигурации заключается в том, что вы передаете все файлы через PHP независимо от расширения файла - это очень необычно и может вызвать проблемы безопасности из-за выполнения кода PHP в файле, где это не ожидалось.

У Сергея все было правильно; добавление $args в команду try_files останавливает сопоставление файла и, таким образом, отправляет Nginx раунд в другом цикле обработки, что является нечетным, поскольку это то, что Nginx пример говорит делать.

Если вы будете точно следовать примеру с:

try_files $uri $uri/ /index.php?q=$uri&$args;

Если $uri и $uri/ не существует, Nginx перейдет к последнему волшебному параметру. Он даже не пытается сопоставить файл, а вместо этого повторно обрабатывает запрос, устанавливая новый путь к /index.php и $args теперь быть q=$uri&$args.

С другой стороны, если у вас есть другое значение в try_files после index.php например

try_files $uri $uri/ /index.php?q=$uri&$args /50x_static.html;

Nginx ищет файл с именем /index.php?q=$uri&$args и его явно не существует, поэтому он переходит на /50x_static.html и перерабатывает это.

Так как $uri перезаписывается, когда Nginx повторно обрабатывает запрос, избегая некоторых тонких изменений. Если вы настроили свою конфигурацию так:

set $originalURI  $uri;
try_files $uri $uri/ /index.php  /50x_static.html;
fastcgi_param  QUERY_STRING  q=$originalURI&$query_string;

Файл, который ищет Nginx, это /index.php это правильное имя, поэтому nginx остановит там обработку. Мы должны скопировать $uri переменная как try_files изменяет его, и поэтому было бы просто /index.php если бы мы просто использовали его после try_files.