Spec-Zone.ru › Apache HTTP Server

Использование RewriteMap

Этот документ дополняет mod_rewrite справочную документацию. В нём описывается использование директивы RewriteMap и приводятся примеры каждого из различных типов RewriteMap.

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

Введение

Директива RewriteMap определяет внешнюю функцию, которую можно вызвать в контексте директив RewriteRule или RewriteCond для выполнения переписывания, слишком сложного или специализированного, чтобы его можно было выполнить только с помощью регулярных выражений. Источником этого поиска может быть любой из типов, перечисленных в разделах ниже и в справочной документации RewriteMap.

Синтаксис директивы RewriteMap выглядит следующим образом:

RewriteMap MapName MapType:MapSource

MapName — произвольное имя, присваиваемое карте и используемое в последующих директивах. Аргументы передаются карте с помощью следующего синтаксиса:

${ MapName : LookupKey }
${ MapName : LookupKey | DefaultValue }

При появлении такой конструкции выполняется обращение к карте MapName и поиск ключа LookupKey. Если ключ найден, конструкция функции карты заменяется на SubstValue. Если ключ не найден, она заменяется на DefaultValue или пустую строку, если значение DefaultValue не указано.

Например, можно определить RewriteMap следующим образом:

RewriteMap examplemap "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. Авторы модулей могут предоставлять дополнительные внутренние функции, регистрируя их через API ap_register_rewrite_mapfunc. По умолчанию доступны следующие функции:

  • toupper:
    Преобразует ключ в верхний регистр.
  • tolower:
    Преобразует ключ в нижний регистр.
  • escape:
    Преобразует специальные символы в ключе в шестнадцатеричные коды.
  • unescape:
    Преобразует шестнадцатеричные коды в ключе обратно в специальные символы.

Чтобы использовать одну из этих функций, создайте RewriteMap со ссылкой на функцию int, а затем используйте её в RewriteRule:

Перенаправление URI на его версию в нижнем регистре

RewriteMap lc int:tolower
RewriteRule "(.*)" "${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 указывается путь в файловой системе к текстовому файлу карты. Каждая строка содержит ключ и одно или несколько значений, разделённых |. При совпадении ключа одно из этих значений выбирается случайным образом.

Например, с помощью следующего файла карты и директив можно организовать случайную балансировку нагрузки между несколькими серверами приложений через обратный прокси-сервер. Изображения отправляются на один из серверов в пуле «static», а все остальные запросы — на один из серверов в пуле «dynamic».

Файл карты переписывания

##
## map.txt -- rewriting map
##

static www1|www2|www3|www4
dynamic www5|www6

Директивы конфигурации

RewriteMap servers "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 examplemap "dbm=sdbm:/etc/apache/mapfile.dbm"

Типом может быть sdbm, gdbm, ndbm или db. Однако рекомендуется использовать утилиту httxt2dbm, поставляемую с Apache HTTP Server: она выберет подходящую библиотеку DBM, соответствующую той, с помощью которой был собран сам httpd.

Чтобы создать файл DBM, сначала создайте текстовый файл карты, как описано в разделе txt. Затем выполните httxt2dbm:

$ httxt2dbm -i mapfile.txt -o mapfile.map

После этого полученный файл можно указать в директиве RewriteMap:

RewriteMap mapname "dbm:/etc/apache/mapfile.map"

Обратите внимание: для некоторых типов DBM создаётся несколько файлов с общим базовым именем. Например, у вас могут появиться два файла с именами mapfile.map.dir и mapfile.map.pag. Это нормально; в директиве RewriteMap достаточно указать только базовое имя mapfile.map.

Кэширование результатов поиска

Найденные ключи кэшируются httpd до тех пор, пока не изменится mtime (время изменения) файла карты или пока сервер httpd не будет перезапущен. Это повышает производительность карт, используемых во многих запросах.

prg: внешняя программа переписывания

При использовании типа MapType prg в качестве MapSource указывается путь в файловой системе к исполняемой программе, реализующей поведение карты. Это может быть скомпилированный двоичный файл или программа на интерпретируемом языке, например Perl или Python.

Эта программа запускается один раз при запуске Apache HTTP Server, а затем взаимодействует с механизмом переписывания через STDIN и STDOUT. То есть для каждого поиска по функции карты она получает один аргумент через STDIN и должна вернуть через STDOUT одну строку ответа, завершённую символом новой строки. Если соответствующего значения нет, программа карты должна вернуть четырёхсимвольную строку «NULL».

Внешние программы переписывания не запускаются, если они определены в контексте, где для RewriteEngine не установлено значение on.

По умолчанию внешние программы переписывания выполняются от имени пользователя и группы, запустивших httpd. В системах UNIX это можно изменить, передав имя пользователя и имя группы третьим аргументом в RewriteMap в формате username:groupname.

Эта возможность использует мьютекс rewrite-map, необходимый для надёжного взаимодействия с программой. Механизм мьютекса и файл блокировки можно настроить с помощью директивы Mutex.

Ниже показан простой пример, который заменяет все дефисы в URI запроса символами подчёркивания.

Конфигурация переписывания

RewriteMap d2u "prg:/www/bin/dash2under.pl" apache:apache
RewriteRule "-" "${d2u:%{REQUEST_URI}}"

dash2under.pl

#!/usr/bin/perl
$| = 1; # Turn off I/O buffering
while (<STDIN>) {
    s/-/_/g; # Replace dashes with underscores
    print $_;
}

Внимание!

  • Старайтесь сделать программу карты переписывания как можно проще. Если программа зависнет, httpd будет бесконечно ждать ответа от карты, из-за чего сервер перестанет отвечать на запросы.
  • Не забудьте отключить буферизацию в программе. В Perl это делается во второй строке примера скрипта: $| = 1; В других языках это, разумеется, может делаться иначе. Буферизованный ввод-вывод заставит httpd ждать вывода, и сервер зависнет.
  • Помните, что существует только один экземпляр программы, запускаемый при старте сервера. Все запросы будут проходить через это единственное узкое место. Это может значительно снизить производительность, если через этот процесс проходит много запросов или сам скрипт работает очень медленно.

dbd или fastdbd: SQL-запрос

При использовании типа MapType dbd или fastdbd в качестве MapSource указывается SQL-оператор SELECT, который принимает один аргумент и возвращает одно значение.

Для выполнения этого оператора необходимо настроить mod_dbd, указав правильную базу данных.

Этот тип MapType имеет две разновидности. При использовании dbd запрос выполняется при каждом обращении к карте, а при использовании fastdbd результаты запросов к базе данных кэшируются. Поэтому, хотя fastdbd работает эффективнее и, следовательно, быстрее, изменения в базе данных не будут учтены до перезапуска сервера.

Если запрос возвращает несколько строк, используется случайная строка из набора результатов.

Пример

RewriteMap myquery "fastdbd:SELECT destination FROM rewrite WHERE source = %s"

Примечание

Имя запроса передаётся драйверу базы данных в качестве метки подготовленного SQL-оператора, поэтому оно должно соответствовать всем требованиям вашей базы данных (например, учитывать регистр символов).

Итоги

Директива RewriteMap может встречаться несколько раз. Для каждой функции отображения используйте отдельную директиву RewriteMap, чтобы объявить соответствующий файл карты переписывания.

Хотя объявлять карту в контексте отдельного каталога (в файлах .htaccess или блоках <Directory>) нельзя, её можно использовать в контексте отдельного каталога.

© 2018 The Apache Software Foundation
Licensed under the Apache License, Version 2.0.
https://httpd.apache.org/docs/2.4/en/rewrite/rewritemap.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API