Рейтинг:1

.htaccess mod_rewrite не улавливает все RewriteRules

флаг de

Существует приложение PHP с маршрутизатором PHP в качестве точки входа для всех запросов, размещенных внутри index.php. Я пытаюсь написать файл .htaccess для пересылки каждого запроса на index.php, кроме запросов API и ресурсов дизайна. Итак, я пытаюсь добиться следующего поведения:

  1. пример.com/api/v1/* должен служить api_v1.php
  2. example.com/любой_путь/resource.css => должен служить ресурс.css если он существует (разрешено несколько расширений; .css это только один пример)
  3. обслуживать index.php за все, что не подпадало под условия выше

Учитывая это .htaccess оценивается сверху вниз, от частных к общим условиям и этому флагу [Л] прервал бы выполнение, если бы что-то совпало, мне удалось придумать следующее .htaccess:

RewriteEngine включен

# Предотвратить перенаправление 301 с косой чертой, когда папка существует и к ней не добавлена ​​косая черта
# Это не проблема безопасности, так как используется PHP-маршрутизатор и все пути перенаправляются
Слэш-каталог выключен

№1. Переписать URL API
Правило перезаписи ^api/v1/(.*)$ api_v1.php [L,NC]

№ 2. Перепишите в index.php, за исключением существующих файлов design/document/favicon/robots
RewriteCond %{REQUEST_URI} !.(css|js|png|jpg|jpeg|bmp|gif|ttf|eot|svg|woff|woff2|ico|webp|pdf)$
RewriteCond %{REQUEST_URI} !^(robots\.txt|favicon\.ico)$ [ИЛИ]
RewriteCond %{REQUEST_FILENAME} !-f
Правило перезаписи ^(.*)$ index.php [L]

№3. Перепишите все остальное
Правило перезаписи ^(.*)$ index.php [L]

Используя приведенный выше код, кажется, что доступ пример.com/api/v1/ не выполняется api_v1.php. Вместо этого он продолжит и выполнит index.php

пример.com/api/v1/ будет работать, только если я удалю все условия после строки 8.

Что я здесь делаю неправильно?

флаг kz
Немного неясно, что именно вы пытаетесь сделать.Должны ли определенные запросы быть переписаны в `index.php`, даже если они существуют в виде физического файла, но не относятся к одному из указанных типов файлов? Должны ли запросы ресурсов (`.css`, `.jpg` и т.д.) по-прежнему переписываться в `index.php`, если они не существуют? (т.е. есть ли у вас законные URL-адреса с таким «расширением файла»?)
caffeine avatar
флаг de
@MrWhite Да, если файл .css не найден, перепишите его в index.php, чтобы я мог правильно обработать ошибку 404 из index.php. Если файл .css существует, обслуживайте его, в противном случае перепишите в index.php
флаг kz
Но как насчет типов файлов, которые вы явно не указали? Должны ли они направляться через `index.php` независимо от того, существуют они или нет? (Вам нужно явно указать список известных типов файлов?)
caffeine avatar
флаг de
Да, чего НЕТ в этом списке, существует оно или нет, его нужно переписать в index.php. Единственная сложность здесь в том, что я также переписываю в index.php имена файлов, которые есть в списке, но НЕ существуют на сервере. По сути, я стараюсь напрямую обслуживать файлы .css, если они существуют, в противном случае переписываю все в index.php (ссылаясь на условия № 2 и № 3)
флаг kz
Я обновил свой ответ полным решением, основанным на ваших комментариях.
Рейтинг:1
флаг kz

кажется, что при доступе к site.com/api/v1/ не выполняется api_v1.php. Вместо этого он продолжит и выполнит index.php

Да, потому что первое правило переписывает запрос на api_v1.php и это в конечном итоге переписывается на index.php по второму правилу (потому что php нет в списке исключенных расширений в первом условие, второе условие также выполняется успешно, поэтому третье условие не обрабатывается (см. ниже) во время второго прохода механизма перезаписи. В каталог контекст (т. .htaccess) л флаг не останавливает всю обработку, он просто останавливает текущий проход через механизм перезаписи. Механизм перезаписи работает до тех пор, пока URL-адрес не пройдет без изменений.

Вы можете решить эту проблему на Apache 2.4, используя КОНЕЦ флаг вместо л, по первому правилу остановить всю обработку переписывающим движком.

Например:

RewriteRule ^api/v1/api_v1.php [NC,END]

(я удалил конец (.*)$ на регулярном выражении, поскольку здесь это не обязательно и делает регулярное выражение незначительно менее эффективным.)

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

№ 2. Перепишите в index.php, за исключением существующих файлов design/document/favicon/robots
RewriteCond %{REQUEST_URI} !.(css|js|png|jpg|jpeg|bmp|gif|ttf|eot|svg|woff|woff2|ico|webp|pdf)$
RewriteCond %{REQUEST_URI} !^(robots\.txt|favicon\.ico)$ [ИЛИ]
RewriteCond %{REQUEST_FILENAME} !-f
Правило перезаписи ^(.*)$ index.php [L]

№3. Перепишите все остальное
Правило перезаписи ^(.*)$ index.php [L]

Если вы запрашиваете что-то.php затем первый условие успешно (потому что .php является нет включены в список). Второе условие также выполнено (это не robots.txt или же favicon.ico). Поскольку второе условие явно объединяется с третьим условием, третье условие не обрабатывается.Все условия соблюдены и запрос переписан на index.php (несмотря на погоду что-то.php есть или нет).

Если, с другой стороны, вы просите ресурс.css затем первый условие терпит неудачу (потому что он имеет .css расширение). Поскольку это условие неявно объединяется по И, дальнейшие условия не обрабатываются и правило не срабатывает. Затем третье правило безоговорочно переписывает ресурс.css к index.php, независимо от того, существует он или нет!

Таким образом, это не проверяет, что запрошенный ресурс (css, jpgи т. д.) «существует», как следует из предыдущего комментария. Третье условие (которое проверяет, что запрос не отображается в файл) обрабатывается только в том случае, если предыдущее условие ИЛИ не выполняется И первое условие успешно. Другими словами, третье условие обрабатывается только тогда, когда вы запрашиваете /роботы.txt - что, я уверен, не входит в ваши намерения.

Другими словами, правила № 2 и № 3 (несмотря на их кажущуюся сложность), похоже, в значительной степени переписываются. все к index.php.

Комплексное решение

На основании ваших дополнительных комментариев:

  • Для подмножества типов файлов обслуживайте ресурс, если он существует. Если ресурс не существует, отправьте запрос на index.php.

  • Для других типов файлов отправьте запрос на index.php, независимо от того, существует этот ресурс или нет.

  • Несколько запросов (т. /роботы.txt и /favicon.ico) не следует отправлять index.php.

Вместо этого попробуйте следующее:

# Предотвратить перенаправление 301 с косой чертой, когда папка существует и к ней не добавлена ​​косая черта
# Это не проблема безопасности, так как используется PHP-маршрутизатор и все пути перенаправляются
Слэш-каталог выключен

# Поскольку установлено "DirectorySlash Off", убедитесь, что списки каталогов mod_auotindex отключены
Параметры - Индексы

RewriteEngine включен

№1. Переписать URL API
RewriteRule ^api/v1/api_v1.php [NC,END]

№ 2. Известные URL/файлы обслуживаются напрямую
RewriteRule ^(index\.php|robots\.txt|favicon\.ico)$ - [КОНЕЦ]

№3.Определенные типы файлов (ресурсы) обслуживаются напрямую, если они существуют
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule \.(css|js|png|jpe?g|bmp|gif|ttf|eot|svg|woff|woff2|ico|webp|pdf)$ - [КОНЕЦ]

№ 4. Перепишите все остальное
RewriteRule ^ index.php [КОНЕЦ]

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

Обратите внимание, что я включил index.php в правиле №2. Это оптимизация, хотя она и не является строго необходимой при использовании КОНЕЦ флаг (в отличие от л) по последнему правилу.

При желании вы можете выбрать перенаправление любого непосредственный просьбы к index.php вернуться к корню (для канонизации URL для поисковых систем). Это на всякий случай /index.php раскрывается (или угадывается) конечному пользователю.

Например, добавьте следующее после первого правила для API:

#1.5 Перенаправление прямых запросов к "/index.php" обратно в "/" (корневой)
Условия перезаписи %{ENV:REDIRECT_STATUS} ^$
Правило перезаписи ^index\.php$ / [R=301,L]

условие который проверяет против REDIRECT_STATUS переменная среды необходима для предотвращения цикла перенаправления — чтобы избежать перенаправления переписанного URL-адреса. (Хотя, опять же, это не является строго обязательным при использовании КОНЕЦ флаг на последнем/переписывающем правиле.)

caffeine avatar
флаг de
Спасибо за обширные объяснения. Это определенно решило мою проблему и принесло очень полезную информацию по этой теме.
Рейтинг:0
флаг ng

Попробуйте поместить условие перезаписи перед каждым правилом, а затем нарушите правило. Другими словами, каждое условие должно иметь свое собственное правило.

условие -> правило
условие -> правило
...

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.