Пример серверного приложения

Лабораторная работа 10

CGI-сценарии

Цель работы

Ознакомиться с организацией исполняемых приложений на web-сервере и изучить технологию программирования CGI-сценариев.

Теоретическая справка

Создание модуля Web

Серверные приложения строятся в C++Builder на основе модуля Web — ком­понента типа TWebModule.Этот компонент может служить контейнером для ряда других компонентов. Сервер типа TWebModuleотсутствует в палитре компонен­тов. Чтобы спроектировать его, надо выполнить команду File | New | Other и в диало­говом окне New Items на странице New выбрать пиктограмму Web Server Application. Перед вами откроется окно, в котором вы должны указать тип модуля. Выберите тип CGI Stand-alone executable — выполняемый модуль CGI. После этого C++Builder создаст в Редакторе Кода заготовку соответствующего модуля и вы увидите окно модуля.

Это окно различается в C++ Builder 6 и 5. В C++Builder 6 вы увидите просто пустое окно, в котором можно размещать компоненты, создающие страницы, осуществляющие связи с базами данных и т.п. Поскольку пока все эти компоненты нам не будут нужны, мы можем о нем временно забыть, кроме одного его свойства: из контекстного меню этого окна мы сможем вызвать редактор действий, с которым будем работать. Если вы откроете окно дерева объектов (Object TreeView), то увидите в нем дерево действий, которые будете вводить в модуль (вначале, ко­нечно, вершина Actions в нем будет пустой). Это окно помогает осуществлять навигацию по действиям.

В C++ Builder 5 окно модуля Web отличается только тем, что два указанных выше окна отображаются отдельными панелями одного окна. К тому же там имеется страница Data Diagram, позволяющая строить диаграммы связей между компонентами. В С++ Builder б подобная страница в модуле просто не нужна, так как аналогичная страница имеется в окне Редактора Кода.

В окне Инспектора Объектов вы можете видеть свойства модуля Web (в С++ Builder 5 вы увидите их, если выделите вершину WebModulel). Основное свойство модуля — Actions.Это собрание действий — объектов типа TWebActi-onltem.Заполняется это список специальным редактором действий, вызываемым щелчком на кнопке с многоточием в окне Инспектора Объектов рядом со свойством Actions. То же окно редактора действий откроется, если вы щелкнете в окне модуля (в C++Builder 5 — на вершине WebModulel) правой кнопкой мыши и выберете из контекстного меню раздел Action Editor. В открывшемся окне быстрой кнопкой Add New вы можете добавить новое действие, кнопкой Delete Selected (вторая слева) — удалить выделенное действие, кнопками со стрелками — изменить последовательность действий.

Каждое действие — объект типа TWebActionltemsсо своими свойствами, методами, событиями. Свойства вы можете увидеть в Инспекторе Объектов, выделив одно из действий. Основное свойство действия — Pathlnfo.Чтобы понять его назначение, надо сообщить некоторые дополнительные сведения об URL. В более общем случае URL может выглядеть, например, так:

http://www.myserv.com/pi/servl.exe/actionl?value=5&Resp=Yes

Начинается URL с указания протокола (HTTP). Далее следует имя хоста — адрес сервера (в приведенном примере «www.myserv.com»). Затем следует имя сер­верного приложения и путь к нему (в приведенном примере «/pl/servl.exe»). По­сле этого, начинаясь с последнего символа слэша и вплоть до вопросительного знака записывается необязательная часть URL, именуемая Pathlnfo. В приведенном примере это «/actionl». Эта информация определяет способ обработки информа­ции серверным приложением. Например, может указываться процедура, которая должна обрабатывать данное сообщение. После символа вопросительного знака следует часть URL, называемая Query — запрос. Обычно она состоит из списка, включающего идентификаторы, символы равенства и значения этих идентифика­торов. Отдельные элементы списка отделяются друг от друга символами "&". В приведенном примере введено имя valueсо значением «5» и имя Respсо значе­нием «Yes». Это информация, которая передается процедуре серверного приложе­ния для обработки.

Теперь мы можем вернуться к рассмотрению свойств действия и к главному свойству — Pathlnfo.Это свойство совпадает с элементом Pathlnfo запроса URL. При получении запроса производится поиск действия, в котором Pathlnfoсовпадает с запроса Pathlnfo. Если такое действие найдено и оно имеет обработчик события OnAction,то выполняются операторы, записанные в этом обработчике. Заго­ловок обработчика имеет вид:

void __fastcall TWebModulel::WebModulelWebActionItemlAction(

TObject *Sender, TWebRequest *Request, TWebResponse *Response, bool SHandled)

Параметр Requestопределяет объект запроса типа TWebRequest.Основное свой­ство этого объекта Query— строка типа string, представляющая часть Query запроса URL. В приведенном выше примере URL она имеет вид: «value=5&Resp=Yes». Другое свойство объекта запроса — QueryFieldsтипа TStrings.Это свойство представляет Query запроса URL в виде списка строк. В приведенном примере он будет содержать две строки: «value=5» и «Resp=Yes». Таким образом, через объект QueryFieldsобработчик события получает доступ к содержащейся в запросе ин­формации. Обращаться к значениям параметров запроса удобно с помощью метода Уа1иев[имя].Например, в приведенном примере выражение Request—>Query-Fields—>Values["Resp"]вернет строку «Yes».

Параметр Responseопределяет объект ответа типа TWebResponse.Основное свойство этого объекта Content— ответ пользователю типа stringв виде текста HTML, имени файла HTML и некоторых других видов.

Параметр Handledопределяет, завершен ли ответ, или объект Responseдол­жен дополнительно формироваться другими действиями. Если требуется, чтобы формирование Responseзавершили другие действия, следует в обработчике задать значение Handledравным false.Тогда, если ответом займется другое действие, ему будет передан объект Response,в котором свойство Contentсодержит текст, занесенный предыдущими действиями.

Мы рассмотрели свойство Pathlnfoобъекта действия и обработчик события OnAction.У объекта действия имеется также свойство Default.Если оно в одном из действий установлено в true,то это действие является действием по умолчанию. Если в модуле не нашлось действия, в котором Pathlnfoсовпадает с запросом, то наступает событие OnActionдействия по умолчанию. Свойство Enabledобъекта действия определяет его доступность.

У самого сервера типа TWebModule,содержащего собрание действий, имеют­ся два события, которые нередко используются для управления сервером. Это со­бытия BeforeDispatch и AfterDispatch,наступающие в начале и в конце обработки запроса. Их заголовки подобны приведенному выше для события OnAction.Прежде всего, при получении запроса наступает событие BeforeDispatch.В его обработчике можно проанализировать запрос и дать на него ответ или произвести настройку сервера, например, сделать с помощью свойств Enabledдоступными или недоступными отдельные действия. Затем наступают события действий. В конце наступает событие AfterDispatch.В его обработчике можно проанализировать ответ, сформированный действиями, и что-то в нем изменить.

Пример серверного приложения

Попробуем посмотреть, как применить на практике все, изложенное в разд. 1. Построим простое серверное приложение, в котором был бы обмен инфор­мацией между клиентом и программой. Пусть наше приложение задаст клиенту вопрос, сколько будет дважды два, и предоставит ему выбор из двух ответов: 4 или 5. Получив ответ клиента, приложение должно сообщить ему результаты этого сложного тестирования.

Закройте все открытые проекты, если они у вас имеются, и создайте модуль сервера (команда File | New | Other, пиктограмма Web Server Application). Откройте ре­дактор действий и занесите в него два действия. Первое действие будет формировать ответ на выбор пользователя.

Его свойство Pathlnfoзадайте равным «/1». Второе действие будет действием по умолчанию. Его назначение — задать пользователю вопрос. Установите свойство Defaultэтого действия в true.

Осталось написать обработчики событий OnActionэтих действий. Для дейст­вия по умолчанию обработчик может иметь вид:

void __fastcall TWebModulel::WebModulelWebActionItem2Action (

TObject *Sender, TWebRequest *Request, TWebResponse *Response, bool SHandled){

Response->Content = "<hl> Знаете ли вы дважды два? </hl>" "<р>Сколько будет 2x2 ?</p><HR>"

"<А HREF=\"/cgi-bin/TwiceTwo.exe/l?4\"> 4</A> или " "<А HREF=\"/cgi-bin/TwiceTwo.exe/l?5\">5</A> ?, <HR>"; Handled = true; }

Этот код возвращает документ HTML. Пользователю предоставляются на выбор две ссылки с текстами «4» и «5». В обеих ссылках Pathlnfo равняется «/1». Таким образом, обе ссылки направляют запрос первому действию, у которого задано это значение Pathlnfo.Но запрос Query в этих двух ссылках разный: «4» и «5». Так что по значению запроса в первом дей­ствии можно распознать, какую из ссылок выбрал пользователь. Обработчик собы­тия OnActionпервого действия может иметь вид:

void __fastcall TWebModulel::WebModulelWebActionItemlAction(

TObject *Sender, TWebRequest *Request, TWebResponse *Response, bool SHandled) { if(Request->Query == "4")

Response->Content = "Ответ 4. Вы прекрасный математик!"; else Response->Content =

"Ответ 5. Вы немного забыли таблицу умножения."; Handled = true; }

Этот обработчик формирует разные ответы в зависи­мости от значения свойства Request.Query.

Сохраните свой проект под именем TwiceTwo.Скомпилируйте его и созданный модуль TwiccTwo.exeпоместите в выполняемый каталог вашего сервера. С помощью любого браузера выполните ваше приложение.

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

<html>

<head>

<title>3naeTe ли вы дважды nBa</title>

</head>

<body>

<p>Знаете ли вы дважды два?</p>

<р>Сколько будет 2x2 ?</р>

<hr>

<р><а HREF="http://mycomputer/cgi-bin/TwoTwo.exe/l?4">4</a>

или

<а HREF="http://mycomputer/cgi-bin/TwoTwo.ехе/1?5">5</а> ? </р>

<hr>

</body>

</html>

Основное отличие от ответа, формировавшегося ранее сервером, заключается в том, что ранее ссылки на выполняемый файл содержали только имя файла «TwiceTwo.exe», а в приведенном тексте ссылки полные: «http://mycomputer/cgi-bin/ TwoTwo.exe». Это необходимо, если файл HTML с данным текстом и выполняемый файл TwoTwo.exe, который вы сейчас создадите, расположены в разных местах. В предыдущем примере такого быть не могло, так как работа велась с одним фай­лом — TwiceTwo.exe.

Сохраните созданный документ в файле TwoTwo.html. Теперь спроектируйте сервер TwoTwo, который будет воспринимать ответ пользователя. Делается это так же, как в рассмотренном ранее примере. Только в данном случае нужно преду­смотреть всего одно действие с Pathlnfo = "\1"< обработчик которого ничем не от­личается от рассмотренного ранее. Так что вы просто можете взять тот же модуль и удалить из него второе действие. Сохраните модуль этого нового сервера под именем «TwoTwo» и nepeHecnfe его выполняемый файл в выполняемый каталог сервера. Откройте любым браузером подготовленный ранее документ TwoTwo.html и убедитесь, что все работает так же, как в предыдущем примере.

Обработка данных из форм

Разберем пример простейшей формы. Как делать формы можно узнать в большинстве учебников по HTML. Особое внимание обратим на передачу параметров.

<form name="form1" method="post" action="project2.exe">

<input type="text" name="textfield">

<input type="submit" name="Submit" value="Запрос">

</form>

После заполнения формы и нажатия кнопки «Запрос» серверному приложению будет передан список всех параметров формы в не слишком хитро зашифрованном виде:

http://server/my/project2.exe?textfield=%D2%E5%F1%F2&Submit=%C7%E0%EF%F0%EE%F1

Нетрудно догадаться, что список параметров идет после знака вопроса в виде «Имя параметра»=«Значение параметра». Параметры отделены друг от друга амперсандом. Если используется местная кодировка, то после процента следует код символа.

Подобную строчку можно увидеть на экране своего браузера, заменив метод передачи параметров с post на get. Мы же будем использовать метод post. Именно этот метод позволяет использовать все возможности библиотеки VCL.

Теперь приведем текст не менее простой программы-сценария.

void __fastcall TWebModule1::WebModule1WebActionItem1Action(

TObject *Sender, TWebRequest *Request, TWebResponse *Response,

bool &Handled)

{

AnsiString A=Request->ContentFields->Values["textfield"];

AnsiString R="<html>\n<h1>Good day, dear "+A+"</h1>\n";

TDateTime D;

D=D.CurrentTime();

R+=D.TimeString() +"</html>";

Response->Content=R;

}

Интерес предоставляют формальные параметры Request и Pesponse. В первом передаются параметры формы, а в Response->Content заключается текст ответа в формате HTML.

Чтобы не писать самому программу разбора строки параметров запроса, можно воспользоваться возможностями библиотеки VCL:

Request->ContentFields->Values["textfield"]

Логика программирования серверной части заключается в формировании строки-ответа Response->Content. По окончании работы программы эта строка передается клиенту:

<html>

<h1>Good day, dear Guest</h1>

13:50:07</html>

Наши рекомендации