Основы Common Gateway Interface и использование CGI для передачи "динамических документов" пользовательским браузерам Web.
В этом уроке мы рассмотрим, как CGI работает и как он вписывается в методологию форм HTML. Но прежде оговоримся: в одном и даже в серии уроков рассмотреть CGI полностью просто-напросто невозможно. Поэтому мы рекомендуем обратиться к источникам (кстати, доступным по Сети) из списка "Дополнительная информация".
КАКОЙ ДОКУМЕНТ ВЫБРАТЬ
В последний раз мы рассматривали два основных метода, при помощи которых формы HTML могут предоставлять пользовательские данные CGI сервера Web - метод get и метод post.
Метод get передает пользовательские данные шлюзам посредством добавления их к пути запрошенного документа. (Термин "документ" используется нами в широком смысле, поскольку большинство CGI-программ создают HTML-форматированный ответ "на лету"; таким образом, ответ - это динамически порождаемая страница или виртуальный документ.)
Когда пользователь щелкает на кнопке Submit в форме HTML, порождаемый формой запрос HTTP содержит текстовую строку, известную как строка запроса; она содержит пользовательские данные для программы CGI. Другая часть запроса содержит имя файла с исполняемой программой CGI - именно эта программа обрабатывает переданные данные.
Шлюз извлекает строку запроса и помещает ее в переменную среды с тем же названием - query_string. Теперь программа CGI может прочитать переменную среды и обработать ее должным образом. В общем, вы помещаете это значение во временную переменную для дальнейшей обработки. Следуя примеру из прошлого номера, пользователь может ответить sky blue на запрос о цвете и large о размере. Значение для переменной среды query_string будет, таким образом, color=sky%20blue&size=large. Все данные, в том числе имена возвращаемых информационных полей и их значения, помещаются вместе с добавлением символов вроде амперсантов (&) и знака процента (%). Помещение текстовой строки во временную переменную позволяет затем развести информацию по соответствующим переменным.
Как видите, параметры передаются программе CGI парами ключ/значение (например, color=sky%20blue или size=large). Эти пары отделены амперсантами. Поскольку использование пробелов и некоторых других символов в URL запрещено, эти символы выражаются знаком процента с последующим шестнадцатеричным значением символа в кодировке ASCII. Таким образом, пробел выражается как %20.
Порядок пар ключ/значение в строке запроса зависит от браузера Web; кроме того, число возвращаемых пар также может меняться. Как указывалось в примере из прошлого урока, если флажок для AppleTalk не выставлен, то пара ключ/значение не передается. После того как программа прочитала переменную среды query_string и поместила ее во временную или рабочую переменную, строку необходимо разобрать грамматически и преобразовать специальные символы (типа пробелов) из шестнадцатеричного представления в исходный вид; затем каждое значение можно присвоить соответствующей переменной в программе.
Метод get не лишен некоторых недостатков. Во-первых, он ограничивает объем передаваемой программе CGI информации; метод просто присоединяет всю передаваемую информацию к URL, а это приводит порою к образованию чрезвычайно длинных URL. В результате передаваемая информация может быть обрезана сервером Web. Вторым существенным недостатком данного метода является то обстоятельство, что определить "гарантированную" длину строки очень сложно, поскольку допустимая длина строки зависит от используемых сервера и браузера. По этой причине неудивительно, что метод post покажется кому-то предпочтительнее.
ОСТАВЬТЕ СВОЕ СООБЩЕНИЕ
Если браузер Web использует метод post, то запрос будет выглядеть следующим образом:
POST /cgi-bin/example.pl HTTP/1.0 Accept: www/source Accept: text/html Accept: text/plain User-Agent: Content-type: application/ x-www-urlencoded Content-length: 28 COLOR=SKY%20BLUE&SIZE=LARGE
Обратите внимание на заголовки типа наполнения (application/x-www-urlencoded). Как правило, формы HTML используют именно этот тип наполнения - когда форма создает запрос, она автоматически задает и его.
При методе post сервер передает содержащуюся в предоставленной форме информацию как стандартный ввод (STDIN) программе CGI. Программа CGI должна знать, какое количество данных считать с STDIN. К счастью, запрос браузера содержит заголовок длины наполнения (content_length). Когда данные формы передаются через CGI, шлюз определяет переменную среды под названием content_length для сообщения об объеме передаваемых данных. Таким образом, программа CGI должна прежде прочесть переменную среды content_length.
Хотя в этом примере мы передаем только небольшой объем данных (28 байт), преимущество использования метода post очевидно, поскольку он позволяет передавать неограниченный объем данных.
Как сервер Web узнает, что данные посланы тем или иным методом? Первый заголовок в запросе браузера определяет тип запроса, а он, в свою очередь, служит для задания значения другой переменной среды, request_method. Однако, если вы разрабатываете приложение при помощи CGI, то, вероятно, вы пишете и клиентскую, и серверную часть приложения, так что вы знаете (решаете), какой метод применяют запросчик и сервер. Например, если формы HTML предоставляют данные по методу get, то программа CGI должна принимать данные с помощью именно этого метода.
СОЗДАНИЕ ВИРТУАЛЬНОЙ СТРАНИЦЫ
Предположим, что данные переданы программе CGI для обработки. Каким образом создается ответ? Очень просто: ответ посылается на стандартный вывод (STDOUT). Это можно сделать с помощью операторов печати; затем шлюз дает указание серверу HTTP (серверу Web) передать ответ браузеру Web в виде документа (обычно документа на HTML).
Простой ответ может выглядеть следующим образом:
HTTP/1.0 200 OK Date: Monday, 24-May-96 11:09:05 GMT Server: NCSA/1.3 MIME-version 1.0 Content-type: text/html Content-length:Simple CGI Test This is a test
Обратите внимание на пустую строку между последней строкой заголовка и началом кода HTML. Данная строка необходима, поскольку она выступает в качестве разделителя между заголовком и основной частью документа.
Теперь мы рассмотрим, каким образом такой ответ в формате HTML можно создать.
Первая строка в Распечатке 1 вызывает интерпретатор Perl из каталога /usr/local/bin (конечно же, интерпретатор может находиться и в другом месте на сервере). Вторая строка - оператор печати - создает строку заголовка. Сервер способен самостоятельно создать большинство строк заголовка, однако заголовок типа наполнения вы должны определить сами. Символ " " - управляющая последовательность перехода на новую строку. Некоторые операционные системы, типа MS-DOS и Windows, используют комбинацию "возврат каретки/перевод строки" для задания новой строки, в то время как другие (например, Unix) используют один символ "новая строка" в конце каждой строки. Способ обработки перевода строки зависит от того, какую операционную систему использует сервер Web.
Заметим, что оператор печати заголовка типа наполнения содержит две команды "новая строка". Эти команды позволяют вставить пустую строку непосредственно за заголовком. (Если вы пытаетесь запустить программу CGI в первый раз, а она не работает, то в первую очередь вы должны обратить внимание на наличие пустой строки между заголовком и основной частью документа.)
Оставшиеся строки, за исключением последней, содержат операторы печати для вывода тегов HTML. Самая последняя строка - это выход из программы.
СОЗДАНИЕ ДИНАМИЧЕСКИХ ДОКУМЕНТОВ
На Распечатке 1 представлен вывод программы CGI. Услуга, предоставляемая CGI, состоит в перенаправлении операторов печати на сервер Web (они направляются обычно на принтер). Сервер, в свою очередь, направляет операторы браузеру Web в виде "виртуального документа HTML". В данном примере создается только один заголовок HTTP (заголовок типа наполнения), все остальные заголовки вставляет сервер Web. В качестве альтернативы программа CGI может генерировать все необходимые строки заголовка - в этом случае сервер доставляет вывод прямо запрашивающему браузеру Web без какой-либо дополнительной обработки. Второй подход называется "неанализируемым заголовком" ("nonparsed header"). В большинстве случаев задача создания заголовков может быть вполне доверена серверу.
Как вы, вероятно, заметили, создаваемые страницы HTML "законсервированы". А как насчет принятия ввода пользователя, обработки его и выдачи ответа в соответствии с вводом? Сценарий на языке Perl из Распечатки 2 демонстрирует эту возможность.
В данном примере мы предполагаем следующее: во-первых, вы создали простую форму на HTML для подачи запроса; во-вторых, запрос подается по методу get; в-третьих, форма содержит одно или более информационных полей.
Первая строка этого сценария вызывает интерпретатор Perl. Вторая строка создает заголовок типа наполнения вместе с требуемой пустой строкой между заголовком и остальной частью документа. Третья и четвертая строки - это начало кода HTML и заголовок документа.
Пятая строка обрабатывает переменную HTTP_USER_AGENT. Когда браузер Web посылает запрос серверу Web, запрос включает обычно ту или иную информацию о заголовке. Один из пунктов информации - тип браузера - CGI помещает в переменную среды HTTP_USER_AGENT. Программа Perl из Распечатки 2 создает локальную строковую переменную под названием "$browser_type" и записывает в нее значение переменной среды HTTP_USER_AGENT.
Шестая строка действует аналогично предыдущей строке. Она берет переменную среды QUERY_STRING и записывает найденную текстовую строку в локальную переменную $query_string. (Обратите внимание, что QUERY_STRING и $query_string - не одни и те же переменные; QUERY_STRING - переменная среды, в то время как $query_string - локальная переменная, используемая только внутри сценария на Perl. Они имеют одно значение, но по существу это два разных объекта.)
Седьмая строка печатает тег HTML, тогда как восьмая создает предложение с уведомлением пользователя о том, какой бразуер Web он использовал при подаче запроса. Следующая строка возвращает пользователю содержимое строки запроса, а оставшиеся строки посылают замыкающие теги HTML.
Данная программа хороша только в качестве учебного примера, но она не очень пригодна для практических целей, поскольку вся необходимая информация содержится целиком в одной переменной среды (QUERY_STRING), причем информация эта (пары ключ/значение с разделителями в виде & и другими служебными символами) неудобочитаема.
При написании программы CGI вы должны будете произвести разбор строки запроса, расшифровку кодировки URL, разбивку строки на отдельные переменные и запись соответствующих значений в каждую из них. Обсуждение того, как производится разбор строки, выходит за рамки нашего урока, однако, если вам знакомы один-два языка программирования (в противном случае вряд ли вы бы собирались писать программы для CGI), то вы должны хорошо себе представлять, как это делать.
НЕ БОЙТЕСЬ ЗАМОЧИТЬ НОГИ
Вы, наверно, обратили внимание на то, что наш урок был посвящен главным образом тому, как передать информацию программе CGI и затем обратно пользователю. Объясняется это тем, что, за исключением процесса ввода и вывода, написание программ CGI немногим отличается от написания любых других программ. Единственное отличие - природа доступа к браузеру Web. Поскольку пользователь ждет, что произойдет какое-нибудь событие, программы CGI должны писаться так, чтобы ответ он получал максимум через несколько секунд.
Алан Франк - тематический редактор LAN Magazine. С ним можно связаться через Internet по адресу: afrank@mfi.com.
Дополнительная информация
The WWW Common Gateway Interface 1.1
http://www.ast.cam.ac.uk/~drtr/draft-robinson-www-interface-00.html
Этот документ, написанный Дэвидом Робинсоном из Кэмбриджского университета, является Internet-проектом с описанием CGI. Первые же строки документа предупреждают, что "проект непригоден для использования в качестве справочника, и он должен цитироваться с пометкой "черновой вариант". Даже учитывая то обстоятельство, что проект может быть изменен или заменен в любой момент, он, тем не менее, весьма полезен для получения информации о текущем состоянии интерфейса.
The Common Gateway Interface
http://hoohoo.ncsa.uuic.edu/cgi/
Национальный центр для суперкомпьютерных приложений Иллинойского университета - это место, где Mosaic появилась на свет. Документ представляет собой хорошее введение в CGI.
Perl for CGI
Practical Extraction and Reporting Language
http://jumpgate.acadsyss.wisc.edu/publishing/cgi/perl.html
Этот документ содержит информацию о языке сценариев Perl.
РАСПЕЧАТКА 1
#!/usr/local/bin/perl
print "Content-type: text/html", " ";
print "", " ";
print "Simple CGI Test ", " ";
print "", " ";
print "This is a test.", " ";
print "", " ";
print "", " ";
exit (0);
РАСПЕЧАТКА 2
#!/usr/local/bin/perl
print "Content-type: text/html", " ";
print "", " ";
print "Regarding Your Request... ", " ";
$browser_type = $ENV{MHTTP_USER_AGENT"};
$query_string = $ENV{MQUERY_STRING"};
print "", " ";
print "The browser you#re using is ", $browser_type, "
"; print "This is the query string that was sent along with your request: ", $query_string, " ";
print "", " ";
print "", " ";
exit (0);