URL rewriting

Материал из Eludia
Перейти к: навигация, поиск

Проблемы

Существует несколько причин, по которым ни одна внутренняя ссылка в сложном WEB-приложении не должна закладываться напрямую в HTML-шаблон. Все гиперссылки на вашей странице должны проходить унифицированную обработку.

Прежде всего, это необходимо для борьбы с браузерным кэшем. Вы можете выдавать какие угодно HTTP-заголовки по поводу даты последнего изменения страницы, но тонкий клиент всё равно будет считать вас дурачком и вместо запроса на обновлённую форму ввода или js-библиотеку доставать старую версию из буфера. Есть только один способ предотвратить это: приписывать случайный параметр к каждой строке запроса.

Кроме того, если только вы не заботитесь об эстетике URL (а в информационных intranet-системах это совершенно бессмысленно), то лучший способ поддержки сессии — это передача её номера через параметры запроса. Единственной универсальной альтернативой является использование cookies. Но, наверное, не стоит долго объяснять разработчику, насколько удобно бывает работать с одного клиента в нескольких сессиях одновременно (что c cookies невозможно), да и запись номера сессии в основной access log может здорово пригодиться при отладке.

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

Решение

В Eludia HTML-код генерируется не напрямую (хотя на кайний случай такая возможность имеется), а при помощи вызова API-процедур draw_form, draw_table и draw_tree. При этом все ссылки задаются в качестве опций href в описаниях кнопок, ячеек и т. п.

Каждое такое описание обрабатывается дважды: сначала в общей части ядра уточняются все опции, а потом при помощи выбранного $_SKIN'а генерируется собственно HTML. Например, описание кнопки сначала уточняется процедурой draw_toolbar_button, которая затем передаёт свой исправленный списко аргументов методу $_SKIN -> draw_toolbar_button.

Так вот, для каждого описания с опцией href вызывается процедура check_href. Она приписывает с исходной ссылке текущий sid, заменяет имеющийся salt на новое случайное значение и производит ещё ряд преобразований.

Наследование параметров

check_href может работать в 2 режимах в зависимости от типа параметра. Если на входе строка,

href => '/?type=users',

то производятся только преобразования, необходимые для работы системы (наследование номера сессии, установка номера экрана и т. п.). Если же передан хэш,

href => {type => 'users'},

то ссылка формируется из текущего %_REQUEST, при этом переопределяются только параметры, явно упомянутые в качестве опций (как в данном случае type).

В зависимости от имени, каждый параметр запроса может:

  • наследоваться всегда (в 1-м и 2-м режиме);
  • участвовать в автонаследовании по запросу (только во 2-м режиме);
  • не наследоваться никогда.

Как отмечалось выше, параметр sid (номер сессии) наследуется всегда, параметры номера экрана __last_query_string и __last_scrollable_table_row не наследуются, но обязательно пересчитываются и устанавливаются. Кроме того, всегда наследуются значения параметров select (признак того, что текущее окно — не основное окно приложения, а расширяемый справочник для списка выбора) и __tree (признак того, что текущее окно вызвано во фрейме explorer like-интерфейса).

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

В отношении прочих параметров действует простое правило: если имя начинается с символа '_', параметр не наследуется никогда, иначе — участвует в автонследовании по запросу.

Наследование при перенаправлении

Функция redirect обрабытывает свои аргументы той же самой check_href, что HTML-функции, соответственно, при перенаправлении клиента параметры изменяются по вышеописанным правилам.

Отметим, что redirect ({action => ""}) вызывается автоматически по завершении обработки действия, если только ранее не был установлен $_REQUEST {__response_sent} (например, в результате явного вызова redirect ({}), в частности, esc).

Скрытые поля форм

Наследование параметров запроса реализовано не только путём модификации URL (собственно "URL rewriting"), но и через поля форм типа hidden.

Однако в данном случае имеется особенность: для форм, порождаемых draw_table, параметры с именами, не начинающимися с '_', наследуются автоматически, а для draw_form их имена необходимо упоминать явно в опции keep_params.

JavaScript

Обработка опций href не сводится исключительно к манипуляциям с параметрами. В ряде случаев, обычная http-ссылка может превратиться в javaScript.

Запрос подтверждения

Обработчик действия часто бывает весьма полезно предварить предупреждающим вопросом. Самая удобная программная реализация такого вопроса — window.confirm на ссылке, ведущей с экранной кнопки. Однако писать каждый раз соответствующий javaScript-код было бы крайне нежелательно. В Eludia достаточно указать опцию confirm

...
href    => {action => 'delete'},
confirm => 'Вы уверены ?!!',
...

и гиперссылка для данной кнопки будет обёрнута в нужный javaScript.

Диалоги

Dialog.gif

По умолчанию http-ссылки открываются в текущем окне. Если требуется указать другое окно (или фрейм), то соответствующее имя следует указать в опции target (наиболее частый пример: скрытый фрейм invisible для обработки действия). Однако есть особый случай, когда в момент активации ссылки целевое окно ещё не существует. То есть страница должна быть окурыта во всплывающем окне.

В Eludia предусмотрен такой приём для показа модальных диалогов: вы оформляете ссылку (опцию href), как обычно, и указываете рядом опцию dialog:

...
href   => "/?type=dmnds_pays&action=create&id_dmnd=$i->{id} ... ",
dialog => {
 title  => 'Платёж',
 after  => '_reload (result)',
 options => {
  width  => 600,
  height => 200,
 },
}
...

Необрабытываемые ссылки

Слишком много автоматики — это не очень хорошо. И для check_href предусмотрен ряд случаев, когда содержимое href передаётся в выходной HTML без обработки:

  • почтовые ссылки ("mailto:...");
  • ссылки-скрипты ("javaScript:...");
  • ссылки с закладкой ("...#").