Перезапись Apache вызывает ошибку сервера 403, когда подлинный каталог существует после перезаписи удаления расширения

Я потратил пару дней, пытаясь создать определенный набор правил, который позволит мне удалить расширения .html из всех файлов в каталог и представить более аккуратные URI.Я использую файл .htaccess в корневом каталоге этого веб-сайта и планирую использовать его на нескольких сайтах, на которых будут возникать такие же проблемы.

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

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.html -f
RewriteRule (.*) $1.html [L]

ErrorDocument 404 https://example.com/404

Это просто и по большей части работает очень хорошо, но когда существует настоящий каталог, кажется, что возникает ошибка сервера 403.

Например, если я посетил example.com/directory_A - я получаю ошибку 403. Однако на самом деле в корневом каталоге есть файл с тем же именем, поэтому я ожидаю, что он действительно представляет example.com/directory_A.html (но, конечно, без html ). В каталоге directory_A находится файл file_B.html , а при посещении example.com/directory_A/file_B отображается file_B.html ] содержание, как ожидалось.

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

1
задан 1 April 2021 в 00:14
1 ответ

, но когда существует настоящий каталог, кажется, что возникает ошибка сервера 403.

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

Ошибка 403 вызвана тем, что mod_dir пытается обслужить документ DirectoryIndex (например, index.html ) из подкаталога / directory_A / , что предположительно выполняет не существует.

В частности, когда вы запрашиваете / directory_A (без косой черты в конце), mod_dir «исправляет» URL, добавляя конечную косую черту через 301 (постоянное) перенаправление. Затем по перенаправленному запросу mod_dir пытается обслужить индекс каталога из этого каталога и запускает 403, если он не существует, а списки каталогов отключены (mod_autoindex).

Чтобы сделать то, что вам нужно, вам нужно запретить mod_dir добавлять завершающую косую черту в физических каталогах с помощью директивы DirectorySlash Off . Затем, чтобы обслуживать /directory_A.html (вместо , проходящего через запрос / directory_A ), вам необходимо удалить первое условие ], что исключает запросы каталогов.

Например:

# Ensure that directory listings are disabled
Options -Indexes

# Prevent mod_dir appending a slash to physical directories
DirectorySlash Off

# Rewrite request to append ".html" extension if it exists
RewriteCond %{DOCUMENT_ROOT}/$1.html -f
RewriteRule (.*) $1.html [L]

Обратите внимание, что списки каталогов должны быть отключены, если вы устанавливаете DirectorySlash Off , иначе mod_autoindex сгенерирует список каталогов при запросе каталога без косой черты в конце и соответствующий файл .html не существует.Обратите внимание на предупреждение системы безопасности в документации Apache относительно директивы DirectorySlash .

В директиве RewriteCond я изменил использование REQUEST_URI , чтобы использовать обратную ссылку из шаблона RewriteRule , чтобы обеспечить единообразие - чтобы гарантировать, что вы всегда используйте одно и то же значение в подстановке RewriteCond TestString и RewriteRule .

Обратите внимание, что запрос / directory_A / (с завершающей косой чертой) все равно приведет к ответу 403, но это ожидается, если вы специально не хотите обрабатывать этот пограничный случай и направлять запросы на / directory_A.html вместо этого? ОБНОВЛЕНИЕ: Это лучше всего достигается путем реализации внешнего перенаправления, чтобы просто удалить завершающую косую черту из URL-адреса, когда существует соответствующий файл .html , поэтому перезапись (см. Выше) делает свое дело и добавляет расширение .html к ответу перенаправления. Это гарантирует, что у вас есть единый канонический URL, что позволяет избежать потенциальной проблемы дублированного контента (где / directory_A и / directory_A / возвращают один и тот же ресурс).

Например, добавьте следующее правило «перенаправления» немедленно перед вышеупомянутым правилом «перезаписи»:

# Remove trailing slash on URL-path when the corresponding ".html" file exists
RewriteCond %{DOCUMENT_ROOT}/$1.html -f
RewriteRule (.*)/$ /$1 [R=302,L]

Это явно не проверяет каталог, поэтому оно также будет работать с другими »файлами. " также. например. / directory_A / file_B / будет перенаправлен на / directory_A / file_B (конечная косая черта удалена).

Сначала протестируйте с 302 (временным) перенаправлением и переходите на 301 (постоянное) перенаправление только тогда, когда вы уверены, что оно работает должным образом, чтобы избежать потенциальных проблем с кешированием.

Вам нужно будет убедиться, что кеш браузера очищен перед тестированием, поскольку предыдущий 301, который mod_dir запускал для добавления конечной косой черты в каталог, будет кэширован браузером.

TBH, лучше избегать таких конфликтов с самого начала и не иметь файлов с тем же базовым именем, что и у физических каталогов, при реализации URL без расширений.


Кроме того:

Оптимизация

Ваша директива, которая добавляет расширение .html , может быть оптимизирована, поскольку в настоящее время она проверяет каждый запрос на наличие файла с .html на конце (что относительно дорого и, вероятно, не нужно). например. запросите /images/myimage.jpg , и ваше правило проверит наличие /images/myimage.jpg.html в файловой системе. Вы можете избежать этих ненужных проверок, исключив запросы, которые уже включают расширение файла (при условии, что ваши URL-адреса не имеют намеренно точек в конце URL-пути, который выглядит как расширение файла).

Например:

# Rewrite request to append ".html" extension if it exists
RewriteCond $1 !\.\w{2,4}$
RewriteCond %{DOCUMENT_ROOT}/$1.html -f
RewriteRule (.*) $1.html [L]

ErrorDocument

 ErrorDocument 404 https://example.com/404

Эта директива, вероятно, неверна.

  1. Когда вы указываете абсолютный URL, он запускает 302 (временное) перенаправление для документа с ошибкой, а не внутренний подзапрос, как должен быть.Следовательно, клиент не видит статус HTTP 404, если вы не установите его вручную в ответе перенаправления. Но в любом случае клиент сначала видит 302.

  2. Здесь вы должны указать фактический URL-адрес документа об ошибке 404, а не версию «без расширения» (которая требует дополнительной обработки), как вы, кажется, делаете здесь.Это полностью внутренний для вашего сервера, клиент не видит этот URL.

Например:

ErrorDocument 404 /404.html

Хотя часто предпочтительнее хранить документы об ошибках в отдельном подкаталоге, который легко исключить из других перенаправлений / перезаписей. например. /errordocs/404.html .

1
ответ дан 24 April 2021 в 00:49

Теги

Похожие вопросы