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

Apache .htaccess RewriteRule и ErrorDocument

у меня есть .htaccess файл :

RewriteEngine On
DirectorySlash Off

RewriteCond %{REQUEST_URI}  !(\.css|\.js|\.png|\.jpg|\.mp4|\.ttf|\.eot|\.woff)$
RewriteRule ^(.*)$ ?page=$1 [NC,L,QSA]

ErrorDocument 404 /e404
ErrorDocument 403 /e404
ErrorDocument 500 /e500

И функция PHP, которая проверяет, существует ли запрошенный URI. Если URI существует в базе данных, он получит содержимое и отобразит страницу, если нет, он получит содержимое страницы с ошибкой 404 и отобразит страницу. (Здесь все ОК)

Проблема в том, что я использую URI с расширениями, которые находятся внутри RewriteCond часть .htaccess файл, что-то вроде example.com/file.css. В этом случае страница перенаправляется на example.com/e404 (это то, что я хочу). Проблема здесь в следующем:

Я не знаю, как получить "неправильный URI" перед перенаправлением на example.com/e404, потому что, когда страница с ошибкой загружается, у меня есть функция внутри страницы для вставки «неправильного URI» в базу данных.

В стороне: Опубликованные вами директивы создадут цикл перезаписи при любой установке Apache по умолчанию, поэтому, возможно, у вас есть другие директивы или другая конфигурация, которую вы не раскрываете в своем вопросе? Во всяком случае, игнорируя это на данный момент, поскольку у вас, похоже, нет такой проблемы.

Я не знаю, как использовать неправильный URI перед перенаправлением на example.com/e404 ...

Но нужна ли вам эта информация перед "перенаправление"? В PHP вы можете просто проверить $_SERVER['REQUEST_URI'] superglobal для получения этой информации (URL-адрес, который привел к ошибке 404). Однако обратите внимание, что он содержит префикс косой черты и строку запроса (если есть), которую вы page В противном случае параметр URL не содержал бы.

Кроме того, чтобы уточнить терминологию, это не строго "перенаправление" на example.com/e404. «Перенаправление» подразумевает внешнее перенаправление HTTP. Apache выдает внутренний подзапрос для документа об ошибке (который похож на перезапись URL, но не совсем).

Одна из потенциальных проблем с вашим кодом заключается в том, что ответ 404 обслуживается довольно круговым способом:

  1. Если file.css не существует, то Apache запускает внутренний подзапрос для /e404
    (это вызывает еще один раунд обработки ...)
  2. поскольку /e404 не оканчивается одним из указанных расширений файла, в дальнейшем он переписывается на ?page=e404 (предположительно index.php?).

Из-за (ненужной) второй перезаписи другие переменные сервера, такие как REDIRECT_URL и REDIRECT_QUERY_STRING (которые также передаются в PHP $_SERVER superglobal) установлены не так, как ожидалось. Обычно для них устанавливается «неправильный URI» (т. Е. Запрошенный URL-адрес, который вызвал 404), но вместо этого они содержат подробную информацию о самом документе об ошибке.

Вы должны сделать это за 1 шаг и избежать повторной перезаписи. Например (при условии index.php файл, обрабатывающий запрос), в документе об ошибке должен быть указан желаемый конечный результат:

ErrorDocument 404 /index.php?page=e404

Между прочим, вам не обязательно явно передавать «статус ошибки» HTTP (т.е. e404) в URL-адресе, так как это доступно в PHP $_SERVER['REDIRECT_STATUS'] суперглобальный.

RewriteRule ^(.*)$ ?page=$1 [NC,L,QSA]

Я предполагал, что вы переписываете на index.php (зарегистрированный DirectoryIndex)? Вместо того, чтобы позволить mod_dir выдать дополнительный подзапрос для DirectoryIndex, вы должны быть явным и включить файл, который вы перезаписываете, в замена. Например:

RewriteRule ^(.*)$ index.php?page=$1 [QSA,L]

(The NC флаг здесь лишний.)

Я не знаю, как использовать неправильный URI перед перенаправлением на example.com/e404 ...

Вернувшись назад, чтобы снова обратиться к вашему первоначальному запросу (как академические упражнения). Вы можете сделать это на Apache 2.4.13+ (хотя я не думаю, что вы необходимость к). В Apache 2.4.13+ вы можете создать динамический ErrorDocument, используя выражения Apache.

Например, чтобы явно передать URL-путь, вызвавший ошибку 404 в URL-адресе самого документа с ошибкой, вы можете сделать что-то вроде следующего:

ErrorDocument 404 /index.php?page=%{escape:%{REQUEST_URI}}&error=404

Параметр URL page затем содержит URL-путь (который включает префикс косой черты, в отличие от вашей перезаписи, которая исключает его). Вдобавок error Параметр URL отправляет статус HTTP (хотя, как упоминалось выше, это не обязательно).