Поиск

Протокол HTTP

На 17-м занятии, "Введение в CGI", мы уже говорили о том, как осуществляется взаимодействие между Web-броузером (таким как Netscape или Internet Explorer) и Web-сервером (например, Apache или IIS) с помощью протокола CGI. Рассматриваемый нами процесс был несколько упрощен. Теперь, после того как вы узнали, что такое CGI, пришло время разобраться с протоколами взаимодействия броузера и сервера более подробно. Чуть позже на этом же занятии вы познакомитесь с некоторыми методами управления этим взаимодействием, позволяющими решать ряд интересных задач.

Упомянутое выше взаимодействие сервера и броузера описывается специальным протоколом, который называется протокол передачи гипертекста (Hypertext Transfer Protocol— HTTP). В настоящее время применяются две версии этого стандарта: HTTP 1.0 и HTTP 1.1 (для обсуждаемых ниже вопросов подходит любая из них).

Документы стандартов, в которых описаны протоколы, используемые в internet, называются Request For Comments, или RFC. Эти документы, поддерживаемые организацией Internet Engineering Task Force (IETF), можно просмотреть в Web no адресу http://vww. ietf.org. Протокол HTTP описан в документах RFC 1945 и RFC 2616. Однако имейте в виду, что эти документы рассчитаны на подготовленных пользователей.

Когда ваш Web-броузер устанавливает соединения с Web-сервером, броузер посылает серверу начальное сообщение, которое выглядит следующим образом:

По строке GET можно судить о том, с какого адреса URL вы пытаетесь получить документ и какую версию протокола используете. В данном случае вы используете версию 1.0 протокола HTTP.

Строка Connection означает, что вы хотели бы оставить это соединение открытым для получения нескольких страниц сразу. По умолчанию броузер создает отдельное соединение для каждого фрейма, страницы и изображения на Web-странице. Директива Keep-Alive просит сервер поддерживать соединение открытым, чтобы можно было принимать несколько элементов, используя одно и то же соединение.

Строки Accept определяют, какие виды данных вы хотели бы принимать с помощью этого соединения. Символы */* в конце первой строки Accept означают, что вы не прочь принимать любые виды данных. Следующая строка (iso-8859-l и остальные) определяет, какое кодирование символов может быть использовано для документа. Строка Accept-Encoding: gzip в данном случае означает, что для сжатия данных, получаемых от сервера, с целью их быстрой передачи может быть использована утилита gzip (GNU Zip). Наконец, строка Accept-Language говорит о том, какие языки приемлемы для этого броузера: английский (США), английский (Великобритания), немецкий, французский и т.д.

В строке Host указывается имя сервера, обслуживающего Web-узел. Благодаря виртуальности обслуживания (пояснения ниже) это имя может отличаться от имени компьютера в URL.

Наконец, броузер идентифицирует себя для Web-сервера как Mozilla/4.51 [en]C-c32f404p (WinNT; U). В Web-терминологии броузер называется пользовательским агентом (user agent).

Затем сервер посылает броузеру ответ, который выглядит примерно так:

За ответом следует содержимое, запрашиваемой вами страницы.

Строка GET в данном случае означает, что сервер собирается передать броузеру Web-страницу. Код возврата 200 свидетельствует о том, что "все" прошло прекрасно. При этом сервер не забывает сказать "несколько слов о себе", идентифицируя себя с помощью строки Server: в данном случае у нас "работает" Web-сервер Netscape-Enterprise/3.5.1G.

Строка Content-Length означает, что броузеру было передано 2222 байта. На основе этих данных ваш броузер теперь сможет вычислить процент завершения загрузки страницы. Строка Content-Type определяет тип посланной обратно страницы. Для HTML-страниц указывается тип text/html, а для изображений может быть установлен тип image/jpeg.

По дате Last-Modified броузер может "судить" о том, была ли изменена страница с момента ее последней загрузки. Большинство Web-броузеров помещает загруженные ранее страницы в локальную кэш-память, чтобы при повторном обращении к этой странице не нужно было ее снова и снова загружать из Internet. При этом полученная от сервера дата сравнивается с датой сохраненной копии, находящейся в кэш-памяти. Если страница на сервере не была изменена, броузер использует локальную копию.

Пример: получение страницы вручную

При желании можно получить Web-страницу вручную. К этой возможности программисты часто прибегают при тестировании CGI-программ, чтобы убедиться в том, что Web-сервер посылает корректные ответы.

Для выполнения этого примера вам потребуется специальная программа, называемая Telnet-клиентом. Telnet-клиент — это программа доступа к удаленному компьютеру с помощью программы эмуляции терминала, исходное назначение которой — обеспечить удаленное подключение к рабочим станциям UNIX. Однако она часто используется для задач отладки протокола HTTP.

Если у вас установлена система UNIX, то в ее поставку обязательно должна входить утилита telnet. Если вы используете Microsoft Windows, то программа telnet автоматически инсталлируется при установке протокола TCP/IP. Чтобы запустить Telnet-клиент, просто используйте команду Выполнить из системного меню Пуск. Если же у вас не установлена программа telnet или вы работаете в системе Macintosh, попробуйте поискать Telnet-клиент в Internet и загрузить его на свой компьютер.

Подключение к Web-серверу с помощью telnet осуществляется следующим образом:

где www.webserver.com — имя Web-сервера, а 80 — номер порта, к которому вы хотите подключиться (именно этот порт обычно используется Web-серверами для установки соединения по протоколу HTTP). Если ваша программа telnet имеет графический интерфейс, то, возможно, придется установить эти значения в специальном диалоговом окне.

После подключения Telnet-клиента вы можете не получить никакого символа приглашения на ввод или сообщения о факте подключения. Не беспокойтесь: это нормальная ситуация. Сервер HTTP ожидает, что клиент "заговорит" первым, поэтому от сервера и не ожидается никакого приглашения. В системе UNIX вы получите сообщение, которое может иметь следующий вид:

Работая в других операционных системах (Windows или Macintosh), вы не увидите подобного сообщения.

Теперь нужно аккуратно и побыстрее ввести следующее:

После ввода этой строки нажмите клавишу <Enter> дважды. Web-сервер должен ответить обычным HTTP-заголовком и страницей верхнего уровня для данного Web-узла, а затем закрыть сеанс связи.

Пример: получение нетекстовой информации

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

Функция header в CGl-модуле информирует броузер о том, данные какого типа он будет получать. Для этого используется заголовок MIME Content-Type, который описывает содержимое данных, следующих за ним. В результате броузер сразу "узнает", что ему нужно делать с полученными данными.

По умолчанию функния header посылает броузеру заголовок Content-Type типа text/html. И броузер "понимает", что за заголовком следует содержимое, представляющее собой текст в формате HTML.

Предупредив броузер о типе получаемых данных, вы можете таким образом управлять способом обработки этих данных броузером. Данные могут выводиться в виде изображений, звука, передаваться дополнительному модулю броузера (browser plug-in) или внешней программе, запускаемой броузером.

Чтобы заставить функцию header послать нечто, отличное от обычного заголовка типа text/html, используйте ключ -type:

Среди тех типов MIME, указываемых в заголовке Content-Type, которые обычно посылаются броузеру, чаще других встречаются text/plain (для текстов, не подлежащих интерпретации броузером), image/gif и image/jpeg (для GIF- и JPEG-изображений), а также application/аррname (для данных, относящихся к конкретному приложению с именем аppnameе). Есть еще специальный тип MIME заголовка Content-Type application/octet-steam, означающий передачу необработанных двоичных данных, которые броузер должен просто сохранить в файле.

Описанные выше типы данных пригодятся вам на случай, если вы захотите создать Web-узел, показывающий "изображение дня" или рекламу Web-страниц. Ежедневное изменение Web-странии для отражения нового образа может превратиться в проблему. А если при этом вас не будет на месте, кто обновит "изображение дня"? Чтобы существенно облегчить себе жизнь, можно создать статическую HTML-страницу и написать CGI-программу на языке Perl, которая бы автоматически каждый день выводила новое изображение.

Для решения проблемы поместите следующий HTML-код в тело Web-страницы:

В приведенном фрагменте HTML-кода обратите внимание, что в дескрипторе <IMG> указана CG1-программа, а не GIF- или JPEG-изображение. Затем вам потребуется папка с изображениями, которых должно хватить хотя бы на месяц. Вы можете использовать любые изображения, главное, чтобы их файлы имели расширение .jpeg. К тому же заметьте, что эту программу можно легко адаптировать для изображений в формате GIF.

CGI-программа daily_image.cgi может иметь вид, представленный в листинге 20.1.

Проведем анализ программы.

  • Строка 7. В этой строке задается каталог, в котором располагаются файлы изображений. Этот каталог можно заменить другим, соответствующим физическому расположению ваших файлов изображений.
  • Строка 8. Как ни странно, но, поскольку эта CGI-программа не выдает никакого текста и поскольку HTML-страница, в которую она встроена, не отображает результат в виде текста, вы не можете просто выводить сообщения об ошибках. Если каталог $imagedir невозможно будет открыть, то будет отображен .jpg-файл, имя которого содержится в переменной $error.
  • Строки 10—16. Эта процедура выводит изображения в стандартный выходной поток, который будет направлен броузеру. На Windows-платформах поток STDOUT рассматривается как текстовый файл, значит, при выводе .jpg-файла в поток STDOUT изображение будет искажено. Поэтому, чтобы сделать дескрипторы STDOUT и IMAGE бинарными, используется функция binmode. Под управлением системы UNIX нет необходимости в использовании функции binmode, но ее присутствие не повредит. Обратите внимание на строку 12: если изображение не удается открыть, нет смысла в выводе сообщения об ошибке, поэтому просто выполняется выход из программы.
  • Строка 19. Эта строка выводит стандартный HTML-заголовок, за исключением того, что в строке Content-Type вместо обычного типа text/html используется image/jpeg.
  • Строка 25. Открывается каталог с изображениями для чтения. Если каталог с изображениями не открывается, то вызывается функция display_image(), которой через переменную $error передается имя файла с изображением ошибки.
  • Строка 26. Эта строка посложнее других, поэтому на ней стоит остановиться. Сначала содержимое каталога читается с помощью функции readdir. Затем из списка извлекаются имена файлов с расширением .jpg. Наконец, полученный список сортируется и присваивается переменной в @jpegs.