Пункт 40. Использование RewriteMap
Этот документ дополняет mod_rewrite
справочную документацию. В нем описывается использование директивы RewriteMap
и приводятся примеры каждого из различных RewriteMap
типов.
Обратите внимание, что многие из этих примеров не будут работать без изменений в вашей конкретной конфигурации сервера, поэтому важно, чтобы вы их поняли, а не просто вырезали и вставляли примеры в свою конфигурацию.
Введение
Директива RewriteMap
определяет внешнюю функцию, которую можно вызывать в контексте
директив RewriteRule
или
RewriteCond
для выполнения перезаписи, которая слишком сложна или слишком специализирована, чтобы ее можно было выполнять только с помощью регулярных выражений. Источником этого поиска может быть любой из типов, перечисленных в разделах ниже и перечисленных в RewriteMap
справочной документации.
Синтаксис директивы RewriteMap
следующий:
RewriteMap MapName MapType : MapSource
MapName — это произвольное имя, которое вы назначаете карте и которое позже будете использовать в директивах. Аргументы передаются карте с помощью следующего синтаксиса:
${
MapName :
LookupKey
}
${
MapName :
LookupKey |
DefaultValue }
Когда возникает такая конструкция, сверяется с картой MapName и просматривается ключ LookupKey . Если ключ найден, конструкция map-функции заменяется на
SubstValue . Если ключ не найден, то он заменяется значением по умолчанию или пустой строкой, если значение по умолчанию не указано.
Например, вы можете определить
RewriteMap
как:
Пример карты RewriteMap "txt:/path/to/file/map.txt"
Затем вы сможете использовать эту карту следующим образом
RewriteRule
:
RewriteRule "^/ex/(.*)" "${examplemap:$1}"
Можно указать значение по умолчанию, если на карте ничего не найдено:
RewriteRule "^/ex/(.*)" "${examplemap:$1|/not_found.html}"
Контекст для каждого каталога и .htaccess
Директиву RewriteMap
нельзя использовать в <Directory>
разделах или
.htaccess
файлах. Вы должны объявить карту в контексте сервера или виртуального хоста. Вы можете использовать созданную карту в своих директивах RewriteRule
и
RewriteCond
в этих областях. Вы просто не можете объявить это в этих областях.
В следующих разделах описываются различные типы MapType , которые можно использовать, и приводятся примеры каждого из них.
int: внутренняя функция
Когда MapType int
используется, MapSource является одной из доступных внутренних RewriteMap
функций. Авторы модулей могут предоставить дополнительные внутренние функции, зарегистрировав их в
ap_register_rewrite_mapfunc
API. Функции, которые предоставляются по умолчанию:
- toupper :
Преобразует ключ во все прописные буквы.
- tolower :
преобразует ключ во все строчные буквы.
- escape :
переводит специальные символы ключа в шестнадцатеричные кодировки.
- unescape :
преобразует шестнадцатеричные кодировки в ключе обратно в специальные символы.
Чтобы использовать одну из этих функций, создайте RewriteMap
ссылку на функцию int, а затем используйте ее в своем RewriteRule
:
Перенаправить URI на версию самого себя со строчными буквами
RewriteMap lc int:tolower
Правило перезаписи "(.*)" "${lc:$1}" [R]
Обратите внимание, что пример, предлагаемый здесь, предназначен только для иллюстрации и не является рекомендацией. Если вы хотите сделать URL-адреса нечувствительными к регистру, рассмотрите возможность использования
mod_speling
вместо этого.
txt: обычные текстовые карты
Когда MapType txt
используется, MapSource — это путь в файловой системе к текстовому файлу отображения, содержащему одну пару ключ/значение, разделенную пробелами, в каждой строке. Опционально строка может содержать комментарий, начинающийся с символа '#'.
Действительный файл карты перезаписи текста будет иметь следующий синтаксис:
# Comment line
MatchingKey SubstValue
MatchingKey SubstValue # comment
При RewriteMap
вызове аргумент ищется в первом аргументе строки, и, если он найден, возвращается значение подстановки.
Например, мы можем использовать файл сопоставления для преобразования названий продуктов в идентификаторы продуктов для более легкого запоминания URL-адресов, используя следующий рецепт:
Конфигурация продукта для идентификатора
RewriteMap product2id "txt:/etc/apache2/productmap.txt"
RewriteRule "^/product/(.*)" "/prods.php?id=${product2id:$1|NOTFOUND}" [PT]
Здесь мы предполагаем, что prods.php
сценарий знает, что делать, когда он получил аргумент о том, id=NOTFOUND
что продукт не найден в карте поиска.
Затем файл /etc/apache2/productmap.txt
содержит следующее:
Сопоставление продукта с идентификатором
##
## productmap.txt - Product to ID map file
##
television 993
stereo 198
fishingrod 043
basketball 418
telephone 328
Таким образом, при http://example.com/product/television
запросе RewriteRule
применяется , и запрос внутренне сопоставляется с /prods.php?id=993
.
Примечание: файлы .htaccess
Приведенный пример создан для использования в области сервера или виртуального хоста. Если вы планируете использовать это в
.htaccess
файле, вам нужно удалить косую черту в начале шаблона перезаписи, чтобы он соответствовал чему-либо:
RewriteRule "^product/(.*)" "/prods.php?id=${product2id:$1|NOTFOUND}" [PT]
Кэшированные запросы
Искомые ключи кэшируются httpd до тех пор, пока mtime
(время изменения) файла карты не изменится или сервер httpd не будет перезапущен. Это обеспечивает лучшую производительность на картах, которые вызываются многими запросами.
rnd: рандомизированный обычный текст
Когда MapType rnd
используется, MapSource — это путь в файловой системе к текстовому файлу сопоставления, каждая строка которого содержит ключ и одно или несколько значений, разделенных знаком |
. Одно из этих значений будет выбрано случайным образом, если ключ совпал.
Например, вы можете использовать следующий файл карты и директивы, чтобы обеспечить случайную балансировку нагрузки между несколькими внутренними серверами через обратный прокси-сервер. Изображения отправляются на один из серверов в «статическом» пуле, а все остальное отправляется на один из «динамического» пула.
Переписать файл карты
##
## map.txt -- rewriting map
##
static www1|www2|www3|www4
dynamic www5|www6
Директивы конфигурации
Серверы RewriteMap "rnd:/path/to/file/map.txt"
RewriteRule "^/(.*\.(png|gif|jpg))" "http://${servers:static}/$1" [NC,P,L]
RewriteRule "^/(.*)" "http://${servers:dynamic}/$1" [P,L]
Итак, когда изображение запрашивается и первое из этих правил соответствует, RewriteMap
ищет строку
static
в файле карты, которая возвращает одно из указанных имен хостов случайным образом, которое затем используется в цели
RewriteRule
.
Если вы хотите, чтобы один из серверов был выбран с большей вероятностью (например, если у одного из серверов больше памяти, чем у других, и поэтому он может обрабатывать больше запросов), просто укажите его несколько раз в файле карты.
static www1|www1|www2|www3|www4
dbm: Хеш-файл DBM
Когда MapType dbm
используется, MapSource — это путь в файловой системе к файлу базы данных DBM, содержащему пары ключ/значение, которые будут использоваться в отображении. Это работает точно так же, как
txt
карта, но намного быстрее, потому что DBM индексируется, а текстовый файл — нет. Это позволяет более быстрый доступ к нужной клавише.
При желании вы можете указать конкретный тип dbm:
Пример карты RewriteMap "dbm=sdbm:/etc/apache/mapfile.dbm"
Тип может быть sdbm
,
или . Однако рекомендуется использовать только утилиту httxt2dbm, поставляемую с HTTP-сервером Apache, поскольку она будет использовать правильную библиотеку DBM, совпадающую с той, которая использовалась при сборке самого httpd. gdbm
ndbm
db
Чтобы создать файл dbm, сначала создайте файл текстовой карты, как описано в разделе txt. Затем запустите
httxt2dbm
:
$ httxt2dbm -i mapfile.txt -o mapfile.map
Затем вы можете сослаться на полученный файл в своей
RewriteMap
директиве:
Имя карты RewriteMap "dbm:/etc/apache/mapfile.map"
Обратите внимание, что с некоторыми типами dbm создается более одного файла с общим базовым именем. Например, у вас может быть два файла с именами
mapfile.map.dir
и mapfiile.map.pag
. Это нормально, и вам нужно использовать только базовое имя mapfile.map
в вашей RewriteMap
директиве.
Кэшированные запросы
Искомые ключи кэшируются httpd до тех пор, пока mtime
(время изменения) файла карты не изменится или сервер httpd не будет перезапущен. Это обеспечивает лучшую производительность на картах, которые вызываются многими запросами.
prg: Внешняя программа перезаписи
Когда MapType prg
используется, MapSource — это путь в файловой системе к исполняемой программе, которая обеспечивает поведение сопоставления. Это может быть скомпилированный двоичный файл или программа на интерпретируемом языке, таком как Perl или Python.
Эта программа запускается один раз при запуске HTTP-сервера Apache, а затем связывается с механизмом перезаписи через
STDIN
и STDOUT
. То есть для каждого поиска функции карты он ожидает один аргумент via STDIN
и должен возвращать одну строку ответа, заканчивающуюся новой строкой, на
STDOUT
. Если нет соответствующего значения поиска, программа карты должна вернуть четырехсимвольную строку " NULL
", чтобы указать на это.
Внешние программы перезаписи не запускаются, если они определены в контексте, для которого не установлено RewriteEngine
значение
on
.
По умолчанию внешние программы перезаписи запускаются от имени пользователя root. Это можно изменить в системах UNIX, передав имя пользователя и имя группы в качестве третьего аргумента
RewriteMap
в username:groupname
формате.
Эта функция использует rewrite-map
мьютекс, необходимый для надежной связи с программой. Механизм мьютекса и файл блокировки можно настроить с помощью
Mutex
директивы.
Здесь показан простой пример, который заменит все тире символами подчеркивания в URI запроса.
Переписать конфигурацию
RewriteMap d2u "prg:/www/bin/dash2under.pl" апач: апач
Правило перезаписи "-" "${d2u:%{REQUEST_URI}}"
dash2under.pl
#!/USR/бен/перл
$| = 1; # Отключить буферизацию ввода/вывода
в то время как (<STDIN>) {
с/-/_/г; # Замените тире символами подчеркивания
напечатать $_;
}
Осторожность!
- Старайтесь, чтобы ваша программа перезаписи карты была как можно более простой. Если программа зависнет, это заставит httpd неопределенно долго ждать ответа от карты, что, в свою очередь, приведет к тому, что httpd перестанет отвечать на запросы.
- Обязательно отключите буферизацию в вашей программе. В Perl это делается второй строкой примера скрипта:
$| = 1;
Конечно, в других языках это будет отличаться. Буферизованный ввод-вывод заставит httpd ожидать вывода, и поэтому он зависнет.
- Помните, что существует только одна копия программы, которая запускается при старте сервера. Все запросы должны будут проходить через это узкое место. Это может привести к значительному замедлению работы, если через этот процесс должно пройти много запросов или если сам сценарий работает очень медленно.
dbd или fastdbd: SQL-запрос
Когда MapType используется dbd
или fastdbd
, MapSource представляет собой инструкцию SQL SELECT, которая принимает один аргумент и возвращает одно значение.
mod_dbd
необходимо настроить так, чтобы он указывал на правильную базу данных для выполнения этого оператора.
Есть две формы этого MapType. Использование MapType dbd
приводит к тому, что запрос будет выполняться с каждым запросом карты, а использование fastdbd
кэширует внутренние поиски в базе данных. Таким образом, хотя
fastdbd
он более эффективен и, следовательно, быстрее, он не будет учитывать изменения в базе данных, пока сервер не будет перезапущен.
Если запрос возвращает более одной строки, используется случайная строка из набора результатов.
Пример
RewriteMap myquery "fastdbd: ВЫБЕРИТЕ пункт назначения ОТ перезаписи ГДЕ источник = %s"
Резюме
Директива RewriteMap
может встречаться более одного раза. Для каждой функции сопоставления используйте одну
RewriteMap
директиву, чтобы объявить ее перезаписывающий файл карты.
Хотя вы не можете объявить карту в контексте каталога ( .htaccess
файлы или
<Directory>
блоки), эту карту можно использовать в контексте каталога.