«Красивые ссылки» — часто запрашиваемая тема, но она редко полностью объясняется. mod_rewrite — это один из способов создания «симпатичных ссылок», но он сложный, его синтаксис очень лаконичен, его сложно найти, а документация предполагает определенный уровень владения HTTP. Может кто-нибудь объяснить простыми словами, как работают «красивые ссылки» и как mod_rewrite может быть использован для их создания?
Другие распространенные имена, псевдонимы, термины для чистых URL-адресов: RESTful URL-адреса, удобные для пользователя URL-адреса, оптимизированные для SEO URL-адреса, Slugged, MVC-URL (вероятно, неправильно)
Чтобы понять, что делает mod_rewrite, вам сначала нужно понять, как работает веб-сервер. Веб-сервер отвечает на HTTP-запросы. HTTP-запрос на самом базовом уровне выглядит следующим образом:
GET /foo/bar.html HTTP/1.1
Это простой запрос браузера к веб-серверу, запрашивающий URL /foo/bar.html
от него. Важно подчеркнуть, что он не запрашивает файл, он запрашивает только какой-то произвольный URL. Запрос также может выглядеть так:
GET /foo/bar?baz=42 HTTP/1.1
Это так же верно и для запроса URL-адреса, и, очевидно, он не имеет ничего общего с файлами.
Веб-сервер — это приложение, которое прослушивает порт, принимает HTTP-запросы, поступающие на этот порт, и возвращает ответ. Веб-сервер полностью свободен отвечать на любой запрос любым способом, который он сочтет нужным / любым способом, которым вы настроили его для ответа. Этот ответ не файл, это HTTP ответ которые могут иметь или не иметь никакого отношения к физическим файлам на любом диске. Веб-сервер не обязательно должен быть Apache, есть много других веб-серверов, которые являются просто программами, которые работают постоянно и подключены к порту, который отвечает на HTTP-запросы. Вы можете написать один самостоятельно. Этот абзац был призван отделить вас от любых представлений о том, что URL-адреса напрямую совпадают с файлами, что действительно важно понять. 🙂
Конфигурация по умолчанию для большинства веб-серверов заключается в поиске файла, соответствующего URL-адресу на жестком диске. Если корень документа сервера установлен, скажем, /var/www
, может ли файл посмотреть /var/www/foo/bar.html
существует и служит этому, если так. Если файл заканчивается на «.php», он вызовет интерпретатор PHP и затем вернуть результат. Вся эта ассоциация полностью настраивается; файл не должен заканчиваться на «.php», чтобы веб-сервер мог запустить его через интерпретатор PHP, а URL-адрес не должен совпадать с каким-либо конкретным файлом на диске, чтобы что-то произошло.
mod_rewrite — это способ перезапись внутренняя обработка запросов. Когда веб-сервер получает запрос на URL /foo/bar
, вы можете перезапись этот URL во что-то еще, прежде чем веб-сервер будет искать файл на диске, чтобы соответствовать ему. Простой пример:
RewriteEngine On
RewriteRule /foo/bar /foo/baz
Это правило говорит всякий раз, когда запрос соответствует «/ foo / bar», переписывайте его в «/ foo / baz». Запрос будет обработан так, как если бы /foo/baz
был запрошен вместо Это может быть использовано для различных эффектов, например:
RewriteRule (.*) $1.html
Это правило соответствует чему угодно (.*
) а также захваты Это ((..)
), затем переписывает его, чтобы добавить «.html». Другими словами, если /foo/bar
был запрошенный URL, он будет обрабатываться как /foo/bar.html
был запрошен. Увидеть http://regular-expressions.info для получения дополнительной информации о сопоставлении регулярных выражений, захвате и заменах.
Другое часто встречающееся правило:
RewriteRule (.*) index.php?url=$1
Это снова сопоставляет что-либо и переписывает его в файл index.php с первоначально запрошенным URL, добавленным в url
параметр запроса. Т.е. для всех поступающих запросов выполняется файл index.php, и этот файл будет иметь доступ к исходному запросу в $_GET['url']
так что он может делать с ним все, что захочет.
Прежде всего, вы помещаете эти правила переписывания в свой файл конфигурации веб-сервера. Apache также позволяет * помещать их в файл с именем .htaccess
в корне вашего документа (то есть рядом с вашими .php файлами).
* Если разрешено основным файлом конфигурации Apache; это необязательно, но часто включено.
mod_rewrite волшебным образом не делает все ваши URL «красивыми». Это распространенное недоразумение. Если у вас есть эта ссылка на вашем веб-сайте:
<a href="/my/ugly/link.php?is=not&very=pretty">
mod_rewrite ничего не может сделать, чтобы сделать ее красивой. Чтобы сделать эту ссылку красивой, вам необходимо:
Измените ссылку на симпатичную ссылку:
<a href="/my/pretty/link">
Используйте mod_rewrite на сервере для обработки запроса к URL /my/pretty/link
используя любой из методов, описанных выше.
(Можно использовать mod_substitute
для преобразования исходящих HTML-страниц и содержащихся в них ссылок. Хотя обычно это больше усилий, чем просто обновление ваших HTML-ресурсов.)
Mod_rewrite может многое сделать, и вы можете создать очень сложные правила сопоставления, включая цепочку нескольких переписываний, передачу запросов на совершенно другой сервис или компьютер, возврат определенных кодов состояния HTTP в виде ответов, перенаправление запросов и т. Д. Это очень мощный инструмент, который можно использовать для очень хорошо, если вы понимаете фундаментальный механизм HTTP-запроса-ответа. Оно делает не автоматически сделать ваши ссылки красивыми.
Увидеть официальная документация для всех возможных флагов и опций.
Расширить на ответ децезе, Я хотел предоставить несколько примеров и объяснение некоторых других функций mod_rewrite.
Все приведенные ниже примеры предполагают, что вы уже включили RewriteEngine On
в вашем .htaccess
файл.
Давайте возьмем этот пример:
RewriteRule ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ /blog/index.php?id=$1&title=$2 [NC,L,QSA]
Правило разделено на 4 раздела:
RewriteRule
— запускает правило перезаписи^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$
— Это называется шаблоном, однако я просто буду называть его левой частью правила — то, что вы хотите переписать сblog/index.php?id=$1&title=$2
— называется заменой или правой частью правила перезаписи — к чему вы хотите переписать[NC,L,QSA]
флаги для правила перезаписи, разделенные запятой, о которых я расскажу позже.Переписанное выше позволит вам сделать ссылку на что-то вроде /blog/1/foo/
и это будет на самом деле загрузить /blog/index.php?id=1&title=foo
,
^
указывает на начало названия страницы — поэтому она будет переписана example.com/blog/...
но нет example.com/foo/blog/...
(…)
Скобки представляют собой регулярное выражение, которое мы можем записать в виде переменной в правой части правила. В этом примере:
([0-9]+)
— соответствует строке длиной не менее 1 символа и только числовыми значениями (т. е. 0-9). На это можно ссылаться с $1
в правой части правила-
или же +
(нота +
экранируется с помощью обратной косой черты, поскольку без экранирования это будет выполняться как регулярное выражение). На это можно ссылаться с $2
в правой части правила?
означает, что предыдущий символ является необязательным, поэтому в этом случае оба /blog/1/foo/
а также /blog/1/foo
переписал бы туда же$
указывает на то, что это конец строки, которую мы хотим сопоставитьЭто параметры, которые добавляются в квадратные скобки в конце правила перезаписи для указания определенных условий. Опять же, есть много разных флагов, которые вы можете прочитать в документация, но я пойду через некоторые из наиболее распространенных флагов:
NC
Флаг без регистра означает, что правило перезаписи нечувствительно к регистру, поэтому для приведенного выше примера правила это будет означать, что оба /blog/1/foo/
а также /BLOG/1/foo/
(или любой вариант этого) будет соответствовать.
L
Последний флаг указывает, что это последнее правило, которое должно быть обработано. Это означает, что если и только если это правило совпадает, никакие дальнейшие правила не будут оцениваться в текущем прогоне обработки перезаписи. Если правило не совпадает, все остальные правила будут опробованы в обычном порядке. Если вы не установите L
флаг, все следующие правила будут применяться к переписанный URL потом.
END
Начиная с Apache 2.4 вы также можете использовать [END]
флаг. Соответствующее правило с ним будет полностью прекратить дальнейшую обработку псевдонима / перезаписи. (Принимая во внимание, что [L]
флаг может часто запускать второй раунд, например, при перезаписи в или из подкаталогов.)
QSA
Флаг добавления строки запроса позволяет нам передавать дополнительные переменные по указанному URL, которые будут добавлены к исходным параметрам получения. Для нашего примера это означает, что что-то вроде /blog/1/foo/?comments=15
будет загружать /blog/index.php?id=1&title=foo&comments=15
R
Этот флаг не тот, который я использовал в приведенном выше примере, но я думаю, стоит упомянуть. Это позволяет вам указать перенаправление http с возможностью включения кода состояния (например, R=301
). Например, если вы хотите сделать редирект 301 в / myblog / to / blog /, вы просто напишите правило примерно так:
RewriteRule ^/myblog/(*.)$ /blog/$1 [R=301,QSA,L]
Переписать условия сделать переписывание еще более мощным, что позволяет вам задавать переписывание для более конкретных ситуаций. Есть много условий, о которых вы можете прочитать в документация, но я коснусь нескольких распространенных примеров и объясню их:
# if the host doesn't start with www. then add it and redirect
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Это очень распространенная практика, которая добавляет ваш домен к www.
(если его там еще нет) и выполните перенаправление 301. Например, загрузка http://example.com/blog/
это перенаправит вас на http://www.example.com/blog/
# if it cant find the image, try find the image on another domain
RewriteCond %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)$ http://www.example.com/$1 [L]
Это немного реже, но это хороший пример правила, которое не выполняется, если имя файла является каталогом или файлом, который существует на сервере.
%{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC]
выполнит перезапись только для файлов с расширением jpg, jpeg, gif или png (без учета регистра). %{REQUEST_FILENAME} !-f
проверит, существует ли файл на текущем сервере, и выполнит перезапись, только если его нет%{REQUEST_FILENAME} !-d
проверит, существует ли файл на текущем сервере, и выполнит перезапись, только если его нетПереполнение стека имеет много другие большие ресурсы, чтобы начать:
^/
префиксы шаблонов для .htaccess
использование.)
И обзоры регулярных выражений даже для новичков:
.*
соответствует чему угодно, даже пустой строке. Вы не хотите использовать этот шаблон везде, но часто в последнем запасном правиле.[^/]+
чаще используется для сегментов пути. Это соответствует чему угодно, кроме косой черты.\d+
соответствует только числовым строкам.\w+
соответствует буквенно-цифровым символам Это в основном сокращение для [A-Za-z0-9_]
,[\w\-]+
для сегментов пути в стиле «slug», используя буквы, цифры, тире -
а также _
[\w\-.,]+
добавляет точки и запятые. Предпочитаю сбежавшего \-
броситься в […]
charclasses.\.
обозначает буквальный период. Иначе .
вне […]
является заполнителем для любого символа.Каждый из этих заполнителей обычно упакован в (…)
скобки как группа захвата. И вся картина часто в ^………$
маркеры начала + конца. Цитировать «шаблоны» необязательно.
Следующие примеры ориентированы на PHP и немного более инкрементны, их легче адаптировать для подобных случаев.
Это просто резюме, часто ссылающиеся на больше вариантов или подробные вопросы.&Как.
/contact
, /about
Сократить несколько имен страниц до внутренних схем файлов проще всего:
RewriteRule ^contact$ templ/contact.html
RewriteRule ^about$ about.php
/object/123
Представляем ярлыки, такие как http://example.com/article/531
к существующим сценариям PHP также легко. Числовой заполнитель может быть просто переназначен на $_GET
параметр:
RewriteRule ^article/(\d+)$ article-show.php?id=$1
# └───────────────────────────┘
/article/with-some-title-slug
Вы можете легко расширить это правило, чтобы учесть /article/title-string
заполнители:
RewriteRule ^article/([\w-]+)$ article-show.php?title=$1
# └────────────────────────────────┘
Обратите внимание, что ваш сценарий должен быть в состоянии (или адаптироваться) отображать эти заголовки обратно в идентификаторы базы данных. Только RewriteRules не может создавать или угадывать информацию из воздуха.
/readable/123-plus-title
Поэтому вы часто будете видеть смешанные /article/529-title-slug
Пути, используемые на практике:
RewriteRule ^article/(\d+)-([\w-]+)$ article.php?id=$1&title=$2
# └───────────────────────────────┘
Теперь вы можете просто пропустить прохождение title=$2
во всяком случае, потому что ваш сценарий, как правило, будет опираться на идентификатор базы данных в любом случае. -title-slug
стал произвольным украшением URL.
/foo/…
/bar/…
/baz/…
Если у вас есть похожие правила для нескольких путей к виртуальным страницам, вы можете сопоставить и сжать их |
альтернативные списки. И снова просто переназначить их на внутренние параметры GET:
# ┌─────────────────────────┐
RewriteRule ^(blog|post|user)/(\w+)$ disp.php?type=$1&id=$2
# └───────────────────────────────────┘
Вы можете разделить их на отдельные RewriteRule
Если это станет слишком сложным.
/date/SWITCH/backend
Более практичным использованием альтернативных списков является сопоставление путей запросов с различными сценариями. Например, чтобы предоставить унифицированные URL-адреса для старых и новых веб-приложений на основе дат:
# ┌─────────────────────────────┐
# │ ┌───────────┼───────────────┐
RewriteRule ^blog/(2009|2010|2011)/([\d-]+)/?$ old/blog.php?date=$2
RewriteRule ^blog/(\d+)/([\d-]+)/?$ modern/blog/index.php?start=$2
# └──────────────────────────────────────┘
Это просто переназначает записи 2009-2011 годов в один сценарий, а все остальные годы неявно — в другой обработчик.
Обратите внимание более конкретное правило приходит первым. Каждый скрипт может использовать разные параметры GET.
/
косые черты /user-123-name
Вы чаще всего видите RewriteRules для имитации структуры виртуальных каталогов. Но вы не обязаны быть нетворческими. Вы можете также использовать -
дефисы для сегментации или структуры.
RewriteRule ^user-(\d+)$ show.php?what=user&id=$1
# └──────────────────────────────┘
# This could use `(\w+)` alternatively for user names instead of ids.
Для также общего /wiki:section:Page_Name
схема:
RewriteRule ^wiki:(\w+):(\w+)$ wiki.php?sect=$1&page=$2
# └─────┼────────────────────┘ │
# └────────────────────────────┘
Иногда целесообразно чередовать /
ограничители и :
или же .
в том же правиле даже. Или снова используйте два RewriteRules для сопоставления вариантов с разными сценариями.
/
слэш /dir
знак равно /dir/
Выбирая пути в стиле каталога, вы можете сделать его доступным с окончательным /
RewriteRule ^blog/([\w-]+)/?$ blog/show.php?id=$1
# ┗┛
Теперь это обрабатывает как http://example.com/blog/123
а также /blog/123/
, И /?$
подход легко добавить к любому другому RewriteRule.
.*/.*/.*/.*
Большинство правил, с которыми вы столкнетесь, отображают ограниченный набор /…/
путь ресурса сегментируется к отдельным параметрам GET. Некоторые скрипты обрабатывать переменное количество опций тем не мение.
Движок регулярных выражений Apache не позволяет произвольно выбирать их число. Но вы можете легко развернуть его в блок правил самостоятельно:
Rewriterule ^(\w+)/?$ in.php?a=$1
Rewriterule ^(\w+)/(\w+)/?$ in.php?a=$1&b=$2
Rewriterule ^(\w+)/(\w+)/(\w+)/?$ in.php?a=$1&b=$2&c=$3
# └─────┴─────┴───────────────────┴────┴────┘
Если вам нужно до пяти сегментов пути, скопируйте эту схему в пять правил. Вы можете, конечно, использовать более конкретный [^/]+
заполнитель каждого.
Здесь порядок не так важен, так как не совпадает. Итак, иметь наиболее часто используемые пути в порядке.
В качестве альтернативы вы можете использовать параметры массива PHP через ?p[]=$1&p[]=$2&p[]=3
Строка запроса здесь — если ваш сценарий просто предпочитает их предварительно разделить.
(Хотя более распространенным является использование правила перехвата всех и позволить самому сценарию расширять сегменты из REQUEST_URI.)
Смотрите также: Как мне преобразовать мои сегменты пути URL в пары ключ-значение строки запроса?
prefix/opt?/.*
Распространенным вариантом является наличие дополнительных префиксов в правило. Обычно это имеет смысл, если у вас есть статические строки или более ограниченные заполнители:
RewriteRule ^(\w+)(?:/([^/]+))?/(\w+)$ ?main=$1&opt=$2&suffix=$3
Теперь более сложная картина (?:/([^/])+)?
там просто заворачивается без захвата (?:…)
группа, и делает это необязательным )?
, Содержится
заполнитель ([^/]+)
будет образец замещения $2
, но будь пуст, если нет середины /…/
дорожка.
/prefix/123-capture/…/*/…whatever…
Как уже говорилось ранее, вам не часто нужны слишком общие шаблоны перезаписи. Однако имеет смысл объединить статические и конкретные сравнения с .*
иногда.
RewriteRule ^(specific)/prefix/(\d+)(/.*)?$ speci.php?id=$2&otherparams=$2
Это необязательно /…/…/…
конечные отрезки пути. Что, конечно, требует сценария обработки, чтобы разделить их, и variabl-римент извлеченные параметры
сам (что к чему WEB- «MVC» рамки делают).
/old/path.HTML
URL не имеют расширений файлов. Вот о чем вся эта ссылка (= URL-адреса являются виртуальными локаторами, не обязательно прямым образом файловой системы).
Однако, если у вас раньше было отображение файла 1: 1, вы Можно выработать более простые правила:
RewriteRule ^styles/([\w\.\-]+)\.css$ sass-cache.php?old_fn_base=$1
RewriteRule ^images/([\w\.\-]+)\.gif$ png-converter.php?load_from=$2
Другие общие виды использования являются переназначением устаревших .html
пути к новым .php
обработчики или просто псевдонимы имен каталогов только для отдельных (реальных / реальных) файлов.
/ugly.html
← → /pretty
Так что в какой-то момент вы переписываете свои HTML-страницы, чтобы содержать только красивые ссылки, как обрисованный в общих чертах deceze.
Тем временем вы все равно будете получать запросы на старый дорожки, иногда даже из закладок. Как обходной путь, вы можете пинг-понг браузеры для отображения / установки
новые URL.
Этот общий трюк включает в себя отправку 30x / Location переадресовывать всякий раз, когда входящий URL следует устаревшей / уродливой схеме именования.
Браузеры будут тогда rerequest новый / красивый URL, который впоследствии переписывается (только внутри) в исходное или новое местоположение.
# redirect browser for old/ugly incoming paths
RewriteRule ^old/teams\.html$ /teams [R=301,QSA,END]
# internally remap already-pretty incoming request
RewriteRule ^teams$ teams.php [QSA,END]
Обратите внимание, как этот пример просто использует [END]
вместо [L]
безопасно чередовать. Для более старых версий Apache 2.2 вы можете использовать и другие обходные пути, кроме переотображения
параметры строки запроса, например:
Перенаправить некрасивый на красивый URL, переназначить обратно на безобразный путь без бесконечных циклов
/this+that+
Это не это довольно в адресной строке браузера, но вы можете использовать пробелы в URL. Для перезаписи шаблонов используйте обратную косую черту \␣
пространства.
Остальное просто "
-цитировать весь шаблон или замену:
RewriteRule "^this [\w ]+/(.*)$" "index.php?id=$1" [L]
Клиенты сериализуют URL с +
или же %20
для пробелов. Тем не менее, в RewriteRules они интерпретируются буквальными символами для всех относительных сегментов пути.
Частые дубликаты:
RewriteCond %{REQUEST_URI} !-f
RewriteCond %{REQUEST_URI} !-d
RewriteRule ^.*$ index.php [L]
Который часто используется PHP-фреймворками или скриптами WebCMS / портала. Фактическое разбиение пути затем обрабатывается в PHP с помощью $_SERVER["REQUEST_URI"]
, Таким образом, концептуально это в значительной степени противоположно обработке URL «per mod_rewrite». (Просто используйте FallBackResource
вместо.)
www.
от имени хостаОбратите внимание, что это не копирует строку запроса и т. Д.
# ┌──────────┐
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] │
RewriteRule ^(.*)$ http://%1/$1 [R=301,L] │
# ↓ └───┼────────────┘
# └───────────────┘
Смотрите также:
· Перезапись URL для разных протоколов в .htaccess
· Общий htaccess перенаправить с www на не-www
· .htaccess — как заставить "WWW." в общем?
Обратите внимание, что комбинации RewriteCond / RewriteRule могут быть более сложными, с совпадениями (%1
а также $1
) взаимодействовать в обоих направлениях даже:
Руководство по Apache — введение в mod_rewrite, Copyright 2015 Apache Software Foundation, AL-2.0
HTTPS://
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://example.com/$1 [R,L]
Смотрите также: https://wiki.apache.org/httpd/RewriteHTTPToHTTPS
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+)$ $1.php [L] # or [END]
Смотрите также: Удаление расширения .php с помощью mod_rewrite
Увидеть: http://httpd.apache.org/docs/2.4/rewrite/remapping.html#backward-compatibility
Увидеть Как я могу заставить свой htaccess работать (субдомены)?
Теперь возьмите это с зерном соли. Не каждый совет может быть распространен на все контексты.
Это просто краткое изложение известных и несколько неочевидных камней преткновения:
mod_rewrite
а также .htaccess
Чтобы фактически использовать RewriteRules в файлах конфигурации для каждого каталога, вы должны:
Проверьте, что ваш сервер имеет AllowOverride All
включен. В противном случае ваш каталог .htaccess
директивы будут игнорироваться, а RewriteRules не будет работать.
очевидно иметь mod_rewrite
включен в вашем httpd.conf
раздел модулей.
Добавить каждый список правил RewriteEngine On
еще. Хотя mod_rewrite неявно активен в <VirtualHost>
а также <Directory>
секции,
на каталог .htaccess
файлы нужны индивидуально.
^/
не будет соответствоватьВы не должны начинать .htaccess
Переписать шаблоны с ^/
обычно:
RewriteRule ^/article/\d+$ …
↑
Это часто встречается в старых уроках. И это было правильно для древних версий Apache 1.x. В настоящее время пути запроса удобно от корки до корки Каталог-родственница в .htaccess
RewriteRules. Просто оставь ведущий /
из.
· Обратите внимание, что начальная косая черта все еще корректна в <VirtualHost>
разделы хотя. Вот почему вы часто видите это ^/?
необязательный для паритета правила.
· Или при использовании RewriteCond %{REQUEST_URI}
ты бы все равно соответствовал лидирующему /
,
· Смотрите также Webmaster.SE: Когда в шаблонах mod_rewrite требуется начальная косая черта (/)?
<IfModule *>
фантикиВы, наверное, видели это во многих примерах:
<IfModule mod_rewrite.c>
Rewrite…
</IfModule>
<VirtualHost>
разделы — если он был объединен с другим резервным вариантом, таким как ScriptAliasMatch. (Но никто никогда не делает это). .htaccess
наборы правил со многими проектами с открытым исходным кодом. Там он просто подразумевается как запасной вариант и по умолчанию сохраняет «некрасивые» URL-адреса.Однако ты не хочу что обычно в вашем собственном .htaccess
файлы.
500
ошибки. Обычно это дает вашим пользователям HTTP 404
ошибки вместо. (Не так много более удобным, если вы об этом думаете.)То, что кажется заманчивым как общая гарантия, часто оказывается препятствием на практике.
RewriteBase
если не нужноМногие примеры копирования + вставки содержат RewriteBase /
директивы. Что в любом случае оказывается неявным значением по умолчанию. Так что вам на самом деле это не нужно. Это обходной путь для причудливых схем перезаписи VirtualHost и неправильных путей DOCUMENT_ROOT для некоторых общих хостеров.
Имеет смысл использовать с отдельными веб-приложениями в более глубоких подкаталогах. В таких случаях это может сократить шаблоны RewriteRule. Обычно лучше указывать относительные пути в наборах правил для каждого каталога.
Смотрите также Как RewriteBase работает в .htaccess
MultiViews
когда виртуальные пути перекрываютсяПерезапись URL в основном используется для поддержки виртуальный входящие пути. Обычно у вас есть только один диспетчерский скрипт (index.php
) или несколько отдельных обработчиков (articles.php
, blog.php
, wiki.php
…) Последний может столкнуться с похожими виртуальными путями RewriteRule.
Запрос на /article/123
например, может сопоставить с article.php
с /123
PATH_INFO неявно. Вы либо должны были бы охранять свои правила тогда с обычным делом RewriteCond
!-f
+!-d
и / или отключить поддержку PATH_INFO, или, возможно, просто отключить Options -MultiViews
,
Что не всегда сказать вам должен. Content-Negotiation — это просто автоматизация виртуальных ресурсов.
Увидеть Все, что вы когда-либо хотели знать о mod_rewrite
если вы еще этого не сделали Объединение нескольких RewriteRules часто приводит к взаимодействию. Это не то, что обычно мешает [L]
флаг, но схема, которую вы примете однажды разбирается.
Вы Можно ре-ре-резаписывать виртуальные пути от одного правила к другому, пока он не достигнет фактического целевого обработчика.
Тем не менее, вы бы довольно часто хотите иметь наиболее конкретные правила (фиксированная строка /forum/…
шаблоны или более ограничительные заполнители [^/.]+
) в рано правила.
Общие правила Slurp-all (.*
) лучше оставить потом из них. (Исключением является RewriteCond -f/-d
охрана как основной блок.)
Когда вы вводите структуры виртуальных каталогов /blog/article/123
это влияет на относительные ссылки на ресурсы в HTML (такие как <img src=mouse.png>
).
Что может быть решено путем:
href="/old.html"
или же src="/logo.png"
<base href="/index">
в ваш HTML <head>
раздел.В качестве альтернативы вы можете создать дополнительные RewriteRules для повторного связывания .css
или же .png
пути к их оригинальным местам.
Но это как ненужное, так и влечет за собой дополнительные перенаправления и затрудняет кеширование.
Смотрите также: CSS, JS и изображения не отображаются с красивым URL
Распространенная неправильная интерпретация заключается в том, что RewriteCond блокирует несколько RewriteRules (потому что они визуально расположены вместе):
RewriteCond %{SERVER_NAME} localhost
RewriteRule ^secret admin/tools.php
RewriteRule ^hidden sqladmin.cgi
Что это не по умолчанию. Вы можете приковать их с использованием [S=2]
флаг. Иначе вам придется их повторять. Хотя иногда вы можете создать «перевернутое» первичное правило для [END] обработки перезаписи на ранней стадии.
Вы не можете соответствовать RewriteRule index.php\?x=y
потому что mod_rewrite сравнивает только с относительными путями по умолчанию. Вы можете сопоставить их отдельно, однако через:
RewriteCond %{QUERY_STRING} \b(?:param)=([^&]+)(?:&|$)
RewriteRule ^add/(.+)$ add/%1/$1 # ←──﹪₁──┘
Смотрите также Как я могу сопоставить переменные строки запроса с mod_rewrite?
.htaccess
против <VirtualHost>
Если вы используете RewriteRules в конфигурационном файле для каждого каталога, то беспокоиться о производительности регулярных выражений бессмысленно. Apache сохраняет
скомпилированные шаблоны PCRE длиннее PHP-процесса с общей структурой маршрутизации. Однако для сайтов с большим трафиком следует учитывать
перемещение наборов правил в конфигурацию сервера vhost после того, как они были испытаны в бою.
В этом случае предпочитайте необязательный ^/?
префикс разделителя каталогов. Это позволяет свободно перемещать RewriteRules между PerDir и сервером
конфигурационные файлы.
Не волнуйтесь.
сравнить access.log
а также error.log
Часто вы можете понять, как RewriteRule плохо себя ведет, просто глядя на ваш error.log
а также access.log
,
Соотнесите время доступа, чтобы увидеть, какой путь запроса был изначально введен, и какой путь / файл не удалось разрешить Apache (ошибка 404/500).
Это не говорит вам, какой RewriteRule является виновником. Но недоступные конечные пути, такие как /docroot/21-.itle?index.php
может дать, где осмотреть дальше.
В противном случае отключите правила, пока не получите предсказуемые пути.
Включить RewriteLog
Увидеть Apache RewriteLog Docs. Для отладки вы можете включить его в разделах vhost:
# Apache 2.2
RewriteLogLevel 5
RewriteLog /tmp/rewrite.log
# Apache 2.4
LogLevel alert rewrite:trace5
#ErrorLog /tmp/rewrite.log
Это дает подробную сводку того, как пути входящих запросов модифицируются каждым правилом:
[..] applying pattern '^test_.*$' to uri 'index.php'
[..] strip per-dir prefix: /srv/www/vhosts/hc-profi/index.php -> index.php
[..] applying pattern '^index\.php$' to uri 'index.php'
Что помогает сузить слишком общие правила и неудачи регулярных выражений.
Смотрите также:
· .htaccess не работает (mod_rewrite)
· Советы по отладке .htaccess переписать правила
Прежде чем задать свой вопрос
Как вы, возможно, знаете, Stack Overflow очень подходит для того, чтобы задавать вопросы по mod_rewrite. Сделать их по теме
Включая предыдущие исследования и попытки (избегать лишних ответов), продемонстрируйте основные регулярное выражение понимание и:
$_SERVER
среда, если речь идет о несоответствии параметров.access.log
а также error.log
чтобы проверить, к чему разрешены существующие правила. Еще лучше, rewrite.log
резюме.Это позволяет быстрее и точнее получать ответы и делает их более полезными для других.
.htaccess
Если вы копируете примеры откуда-то, постарайтесь включить # comment and origin link
, Хотя это просто плохие манеры опускать атрибуцию,
это часто действительно вредит обслуживанию позже. Документирование любого кода или учебного источника. В частности, пока вы не говорите, вы должны быть
тем более заинтересованы в том, чтобы не относиться к ним, как к волшебным ящикам
Отказ от ответственности: просто любимая мозоль. Вы часто слышите красивые схемы перезаписи URL, называемые ссылками «SEO» или что-то в этом роде. Хотя это полезно для примеров поиска в Google, это устаревший неправильный номер.
Ни одна из современных поисковых систем действительно не обеспокоена .html
а также .php
в сегментах пути, или ?id=123
Строки запроса по этому вопросу. Поисковые системы старых, таких как AltaVista, сделал избегайте сканирования сайтов с потенциально неоднозначными путями доступа. Современные сканеры часто даже жаждут глубоких веб-ресурсов.
То, для чего «концептуально» должны быть использованы концептуально, это создание сайтов удобный.
/common/tree/nesting
,Однако не жертвуйте уникальными требованиями к конформизму.
Существуют различные онлайн-инструменты для генерации RewriteRules для большинства URL-адресов с GET-параметрами:
В основном просто вывод [^/]+
общие заполнители, но, вероятно, достаточно для тривиальных сайтов.
Многие основные схемы виртуальных URL могут быть реализованы без использования RewriteRules. Apache позволяет запускать сценарии PHP без .php
расширение, и с виртуальным PATH_INFO
аргумент.
Настоящее время AcceptPathInfo On
часто включен по умолчанию. Что в основном позволяет .php
и URL других ресурсов для переноса виртуального аргумента:
http://example.com/script.php/virtual/path
Теперь это /virtual/path
появляется в PHP как $_SERVER["PATH_INFO"]
где вы можете обрабатывать любые дополнительные аргументы, как вам нравится.
Это не так удобно, как иметь отдельные сегменты входного пути Apache в $1
, $2
, $3
и передавая их как отдельные $_GET
переменные в PHP. Он просто эмулирует «красивые URL» с меньшими усилиями по настройке.
.php
расширениеСамый простой вариант также отказаться от .php
«Расширения файлов» в URL-адресах включает:
Options +MultiViews
Это имеет выбор Apache article.php
для HTTP-запросов на /article
из-за совпадения базового имени. И это хорошо работает вместе с вышеупомянутой функцией PATH_INFO. Таким образом, вы можете просто использовать URL-адреса, такие как http://example.com/article/virtual/title
, Это имеет смысл, если у вас есть традиционное веб-приложение с несколькими точками вызова / сценариями PHP.
Обратите внимание, что MultiViews имеет другое / более широкое назначение. Это влечет за собой очень незначительный снижение производительности, потому что Apache всегда ищет другие файлы с соответствующими базовыми именами. Это на самом деле предназначено для Content-Negotiation, поэтому браузеры получают лучшую альтернативу среди доступных ресурсов (таких как article.en.php
, article.fr.php
, article.jp.mp4
).
.php
скриптыБолее направленный подход, чтобы не носить с собой .php
суффиксы в URL есть настройка обработчика PHP для других файловых схем. Самый простой вариант — переопределить тип MIME / обработчика по умолчанию через .htaccess
:
DefaultType application/x-httpd-php
Таким образом, вы можете просто переименовать article.php
сценарий просто article
(без расширения), но все равно обрабатывать его как PHP-скрипт.
Теперь это может иметь некоторые последствия для безопасности и производительности, потому что все файлы без расширений теперь будут передаваться через PHP. Следовательно, вы можете установить это поведение только для отдельных файлов:
<Files article>
SetHandler application/x-httpd-php
# or SetType
</Files>
Это в некоторой степени зависит от настроек вашего сервера и используемого PHP SAPI. Общие альтернативы включают ForceType application/x-httpd-php
или же AddHandler php5-script
,
Снова обратите внимание, что такие настройки распространяются от одного
.htaccess
в подпапках. Вы всегда должны отключить выполнение скрипта (SetHandler None
а такжеOptions -Exec
или жеphp_flag engine off
и т. д.) для статических ресурсов, а также для загрузки / каталогов и т. д.
Apache предоставляет множество возможностей mod_alias
функции — которые иногда работают так же, как mod_rewrite
s RewriteRules. Обратите внимание, что большинство из них должны быть настроены в <VirtualHost>
раздел, однако, не в каждом каталоге .htaccess
конфигурационные файлы.
ScriptAliasMatch
в первую очередь для сценариев CGI, но также должен работать на PHP. Это позволяет регулярные выражения, как и любой RewriteRule
, На самом деле это, пожалуй, самый надежный вариант для настройки универсального фронт-контроллера.
И равнина Alias
помогает с несколькими простыми схемами переписывания.
Даже равнина ErrorDocument
Директива может быть использована, чтобы позволить PHP-скрипту обрабатывать виртуальные пути. Обратите внимание, что это хитрый обходной путь, однако запрещает что-либо, кроме запросов GET, и затопляет error.log по определению.
Увидеть http://httpd.apache.org/docs/2.2/urlmapping.html для дальнейших советов.