Методичка: Разработка Web-приложений

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

<form action="http://localhost/" method="post">

<input type=hidden name="param1" value="1">

<input type=hidden name="param2" value="2">

<input type=submit></form>

Как видно из примера, параметры записываются в виде

[имя параметра 1]=[значения параметра 1]&[имя параметра 2]=[значения параметра 2]&...

Такой вид записи является стандартным и носит название CGI интерфейса (Common Gateway Interface - базовый интерфейс гейтов (gate - врата, ещё одно название серверов)). Все данные, отсылаемые браузером, обработавшим HTML к серверу записываются именно в таком формате. При этом символы, отличные от печатных ANSI, записываются в формате %NN, где NN - это шестнадцатиричный код символа. К примеру, пробел будет записан как %20, а символ % - как %25 (см.ASCII & ANSI Character Codes).

Так как русские кириллические символы не входят в набор печатных ANSI символов, то в HTTP заголовках они тоже заменяются подобным образом.

Наиболее часто употребим ещё один метод запроса - "GET". Фактически все запросы, не требующие отправки данных - например запрос страницы, производятся этим способом. Впрочем, данные можно отправлять и GET методом - изменим форму запроса:

<form action="http://localhost/" method="get">

<input type=hidden name="param1" value="1">

<input type=hidden name="param2" value="2">

<input type=submit></form>

и получим следующий HTTP запрос:

GET http://localhost/?param1=1&param2=2 HTTP/1.1

Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

Accept-Language: ru

User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)

Host: localhost

Proxy-Connection: Keep-Alive

Как видно, строка "param1=1&param2=2" переместилась выше и добавилась к строке "http://localhost/" после знака "?". Так же изменилось первое слово в HTTP заголовке, остальное осталось без изменения.

Достоинством метода GET является то, что в строке браузера видно, какие данные были отправлены. К недостаткам же относится то, что длина отправляемых данных таким способом (в отличие от метода POST) ограничена - некоторые серверы, как и некоторые браузеры, имеют лимит на длину адреса запрашиваемого документа. Соответственно адрес с длинной строкой запроса может быть либо обрезан, либо сервер возвратит ошибку "414 Request-URI Too Long".

HTTP запрос

Разберём по строкам HTTP заголовок запроса:

Первая строка, первое слово - имя метода запроса. Это слово может быть одно из следующих:

OPTIONS

GET

HEAD

POST

PUT

DELETE

TRACE

CONNECT

В данной статье я буду касаться прежде всего двух методов - GET и POST, подробнее об остальных читайте тут - RFC 2616, Section 5. Вкратце лишь опишу действия остальных:

Метод HEAD по действию практически идентичен методу GET с одним отличием - в ответе на метод HEAD сервер выдаёт только HTTP заголовок, не выдавая содержимого документа.

Метод PUT по действию идентичен методу POST, но как и HEAD выдаёт только заголовок HTTP.

Метод OPTIONS выдаёт все действия, которые можно совершить с документом.

Метод DELETE указывает серверу, чтобы он предпринял попытку к удалению документа. Возможным ответом является ошибка политики безопасности ("403 Forbidden").

Методом TRACE можно получить путь запроса до сервера, список узловых точек, гейтов (Gate), путь через прокси-сервера.

Метод CONNECT возвращает есть ли связь с сервером и поддерживает ли сервер HTTP протокол.

Сразу после ключегого слова, определяющего метод, идёт символ пробела и указан URI документа запрашиваемого с сервера. После URI документа идёт ещё один символ пробела и название протокола (строка "HTTP/1.1").

Что такое URI? URI расшифровывается как Uniform Resource Identifier (формат записи индитефикатора ресурса), полностью он описан тут - RFC 2396, а нас интересует лишь то, как с помощью его записывается адрес документа. Для HTTP существует разновидность стандарта URI, называемая URL (Uniform Resource Location - формат записи нахождения ресурса), к примеру

http://devresource.org:80/javalinks/catalog.php3?name=java&cat=2#section1

Из приведённого примера URL можно выделить логические части:

1) [http://]

2) [devresource.org:80/javalinks/catalog.php3]

3) [?name=java&cat=2]

4) [#section1]

часть (1) указывает на протокол доступа к документу, часть (2) - можно разбить на две части -

[devresource.org]

[:80]

[/javalinks/catalog.php3]

это имя хоста (вместо имени devresource.org может стоять и IP адрес), порт сервера через символ ":" и путь (path) до документа от корня (root) сервера.

Стандартным портом для HTTP сервера является порт 80 и, поэтому, его можно не указывать. Внимание! Если порт сервера отличается от 80, то в URL его нужно обязательно указать.

Третья часть URL - это GET часть запроса, отделена от документа символом "?".

И, наконец, последняя часть URI - "секция", отделённая символом "#". При HTML форматировании в документа можно положить закладку (по другому - установить якорь, он же anchor, отсюда и название HTML тега <A>). Если в URI ресурса указана секция, то в HTML ищется одноимённая закладка, а браузер при отображении документа показывает текст, отмеченный якорем.

К примеру, для HTML документа sample.html

...

test 24

<a name="section1">test 25</a>

test 26

<a name="section2">test 27</a>

test 28

...

при вызове sample.html#section1 документ будет проскролирован до закладки "section1", а при указании sample.html#section2 - будет показано место, помеченное в документе, как "section2".

Части URL с номерами (3) и (4) являются необязательными. Если нет необходимости, их можно не указывать. В первой строке HTTP запроса так же можно указать не полный URL, а лишь путь до документа - к примеру так:

GET /#section1 HTTP/1.1

или так:

GET /javalinks/catalog.php3?name=java&cat=2#section1 HTTP/1.1

В таких случаях имя хоста берётся из параметра HTTP запроса "Host".

Внимание! Имя протокола в URI в первой строке заголовка сигнализирует серверу о том, что путь до документа указан вместе с именем хоста. То есть, если послать серверу заголовок, начинающийся со строки

GET localhost/?param1=1&param2=2 HTTP/1.1

то сервер будет искать документ

http://localhost/localhost/?param1=1&param2=2

а не

http://localhost/?param1=1&param2=2

Как и каждая строка HTTP заголовка, первая строка запроса заканчивается символом переноса строки ("\n").

Параметры HTTP запроса

Далее приведены основные параметры для HTTP заголовка. Каждая строка, содержащая параметр начинается с ключевого слова (например "Host"), потом идёт символ двоеточие, пробел, значение параметра и символ переноса строки. Приведённые параметры соответствуют стандарту RFC 2616 (HTTP/1.1). Здесь приводится не весь список возможных полей запроса и их значений.

Host: localhost

Этот параметр содержит имя хоста, например "localhost" или "localhost:80" (если порт 80, то его можно не указывать, если порт отличается от 80, то его нужно обязательно указать). Это второй обязательный параметр HTTP заголовка (первый - HTTP метод и имя протокола).

Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

В этом параметре через запятую указаны MIME типы документов, которые способен обработать браузер. Так же в MIME типе указываются доступные к обработке кодировки документов. Подробнее о стандарте MIME смотрите тут - RFC 2045. Символ "*" в указании типа означает, что браузер может обработать весь класс документов. К примеру, image/* означает, что браузер может обработать и image/gif, и image/x-xbitmap, и image/jpeg, и image/pjpeg и вообще любые документы изображений, а заключительный тип - */* указывает, что браузер обработает любые документы, присланные сервером. На деле это обычно означает, что если MIME тип присланного сервером документа браузеру неизвестен, то он предложит сохранить его на диск.

Accept-Language: ru, en

Accept-Charset: windows-1251, KOI8-R

Эти параметры отвечают за языки. В первом - через запятую указываются предпочтительные языки для сервера. В частности Google.com, обработав этот параметр, перенаправит вас на русскоязычную страничку. Во втором - кодировка, в которой закодированы символы в CGI запросе. Также через запятую могут быть указаны предпочитаемые кодировки для ответа сервера.

Accept-Encoding: compressed, gzip

Тут указаны возможные варианты пересылки данных. В частности, я привёл в пример запроса, показывающего, что браузер готов принимать HTML документ в сжатом виде.

User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; .NET CLR 1.0.3705)

Имя HTTP клиента. Многие браузеры тут же указывают операционную систему, плагины и прочие нашлёпки.

Referer: http://localhost/?test=test

Очень полезный параметр. Значением этого поля является URL ресурса, с которой был осуществлён переход. Фактически, когда вы нажимаете на ссылку в HTML документе, скорее всего адрес этого документа будет записан в этот параметр.

Cookie: param1=value1; param2=value2

В этом параметре браузер отправляет cookie (или просто куки) - данные, записанные сервером на компьютер клиента. Как видно, куки отправляются не с помощью CGI интерфейса, их форматирование отличается:

[имя параметра1]=[значение параметра1]; [имя параметра2]=[значение параметра2]; ...

Впрочем, значения параметров кодируются точно так же, как и в CGI - "неправильные" символы заменяются с помощью %NN. Подробнее о куках читайте тут - Cookie Specification.

Range-Unit: 2015 | 1024

Очень полезный параметр, позволяющий получить с сервера не весь документ, а только его часть. Именно этот параметр используют менеджеры докачек типа flashget. В данном примере указано, что клиент хочет получить кусок документа, начиная с 2015 байта и длиной в 1 килобайт. Если сервер поддерживает докачку и документ не является динамическим, то будет выдана запрашиваемая часть. В противном случае сервер вернёт ошибку о том, что действие не поддерживается или начнёт выдавать документ полностью.

Pragma: no-cache

Cache-Control: no-cache, must-revalidate

Параметры, указывающие серверу, что этот документ не надо брать из кэша. Другие варианты значений могут быть: "public" - документ является публичным, его может брать любой клиент из кэша "private" - документ является приватным, только для данного клиента "no-store" - не сохранять в кэш "no-transform" - не модифицировать документ, уже содержащийся в кэше "must-revalidate" - обязан обновить документ, лежащий в кэше (и браузер и прокси) "proxy-revalidate" - в кэше должен обновить только прокси сервер "max-age=[seconds]" - сохраняет в кэш на количество секунд, указанных в параметре, начиная со времени сохранения; по истечению этого времени, документ удаляется Допустимо указание параметра в следующем виде:

Pragma: must-revalidate, max-age=1000

но некоторые комбинации значений могут вызвать ошибку "400 Bad request"

Proxy-Connection: Keep-Alive

Параметр указывает на то, что соединение с сервером будет поддерживаться постоянно. Другой вариант -

Proxy-Connection: close

означает, что браузер уже послал все данные серверу и теперь будет только ждать ответа.

Для запроса к серверу, обязательными являются лишь два параметра: первая строка, уточняющая метод запроса и несущая адрес ресурса и параметр "Host", содержащий имя хоста и порт сервера.

Отправка файла методом POST

Отдельно стоит рассказать об отправке файлов с помощью метода POST. Для того, чтобы отправить файл этим методом, нужно в форме отправки сообщений указать специальный параметр "enctype='multipart/form-data'":

<form action='http://localhost' method=post enctype='multipart/form-data'>

<input type='hidden' name='test' value='test'>

<input type='file' name='testfile'>

<input type='submit' value='send'></form>

Допустим, мы отправляем файл "c:\test.txt" размера 14 байт, содержащий текст "This a test!!!". В этом случае данные будут отправлены следующим образом:

POST http://localhost/ HTTP/1.1

Content-Type: multipart/form-data;

boundary=---------------------------7d33188e01e4

Host: localhost

Content-Length: 254

-----------------------------7d33188e01e4

Content-Disposition: form-data; name="test"

test -----------------------------7d33188e01e4

Content-Disposition: form-data; name="testfile"; filename="c:\test.txt"

Content-Type: text/plain

This a test!!!

Как видно из примера, добавляется ещё два HTTP параметра -

Content-Type: multipart/form-data; boundary=

---------------------------7d33188e01e4

Эта строка говорит, что все отсылаемые данные будут передаваться по частям, а делителем этих частей будет выступать строка "-----------------------------7d33188e01e4" и перенос строки после неё. Вообще-то, делителем может выступать совершенно любой набор символов, лишь бы подобного не было в передаваемых данных.

Content-Length: 342

Этот параметр сообщает серверу количество данных, содержащихся после HTTP заголовка.

Ну и сами данные передаются с помощью HTTP-subheader (субзаголовок HTTP)

Content-Disposition: form-data; name="test"

Тут указывается название переменной, после чего идут два символа переноса строки и сами данные. Конец данных означает либо символ переноса строки и делитель (boundary), либо конец полученых данных.

Другой субзаголовок -

Content-Type: text/plain

Он передаёт серверу MIME тип отправляемого файла. Нужно заметить, что при передаче данных таким способом, непечатные символы не заменяются на %NN, а отправляются как есть.

HTTP ответ

Перейдём к ответу сервера. Вот пример ответа сервера клиенту (сервер выдаёт текстовый файл, содержащий строку "This a test!!!"):

HTTP/1.1 200 OK

Date: Mon, 07 Apr 2003 14:40:25 GMT

Server: Apache/1.3.20 (Win32) PHP/4.3.0

Keep-Alive: timeout=15, max=100

Connection: Keep-Alive

Transfer-Encoding: chunked

Content-Type: text/plane

This a test!!!

Ещё один пример, сервер выдаёт файл test.zip:

HTTP/1.1 200 OK

Date: Mon, 07 Apr 2003 14:51:19 GMT

Server: Apache/1.3.20 (Win32) PHP/4.3.0

Last-Modified: Mon, 07 Apr 2003 14:51:00 GMT

Accept-Ranges: bytes

Content-Length: 673

Keep-Alive: timeout=15, max=100

Connection: Keep-Alive

Content-Type: application/zip

Content-Disposition: attachment; filename=test.zip

Pragma: no-cache

....(содержимое zip файла)

Тут мы тоже видим HTTP заголовок, отделённый от тела документа двумя символами переноса строки.