IT • archiv

rus / eng | Логин | Комментарий к колонке | Печать | Почта | Клуб




Колонки


HTTP протокол и работа с Web в Java. Протокол HTTP

 
( Константин Андрухин )

Протокол HTTP работает поверх TCP/IP. Фактически же это означает, что клиент открывает сокет до сервера, пишет туда HTTP запрос (request), сервер читает запрос, обрабатывает его и посылает результат обработки (response) обратно клиенту.

Любой HTTP запрос, как и любой ответ по этому протоколу состоит из двух блоков: заголовок и собственно данные. Заголовок отделён от данных двойным символом переноса строки (в Java это будет "\n\n", хотя допускается и "\r\n\r\n" для платформы Windows).

Так как HTTP был изначально ориентирован на пересылку прежде всего текстовой информации, то HTTP заголовок является полностью текстовым, все символы, передающиеся в нём, являются печатными (прежде всего цифры и литеры латинского алфавита A-Z, a-z, а также набор других отображаемых символов + символ переноса строки "\n" или "\r\n"). При передаче в HTTP заголовке других символов, будет выдана ошибка "400 Вad request".

HTTP запросы. CGI интерфейс. Методы

Разберём подробнее HTTP запрос клиента. Он может выглядеть например так:

POST http://localhost/ 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

Взглянув на пример, можно заметить, что запрос начинается со слова "POST". Это слово означает метод передачи данных на сервер, в котором дополнительные данные запроса (строка "param1=1&param2=2") передаются после заголовка.

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

<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 заголовок, отделённый от тела документа двумя символами переноса строки.

Разберём заголовок. Он начинается с названия протокола "HTTP/1.1", после чего идёт пробел, затем — код возврата "200 OK". После кода возврата идёт символ переноса строки.

Коды ответов сервера

Вот основные коды возврата, определённые для серверов:

Коды с номером типа 1xx: информационный — запрос послан, идёт процесс:

  • "101 Switching Protocols" — переключение протокола

Коды с номером типа 2xx: удачное завершение — запрос полностью послан, прочитан/понят сервером и принят им:

  • "200 OK" — запрос успешно получен, понят, принят и выполнен
  • "201 Created" — создано
  • "202 Accepted" — принято
  • "203 Non-Authoritative Information" — нерабочая информация
  • "204 No Content" — нет информации к ответу
  • "205 Reset Content" — очистка ответа
  • "206 Partial Content" — выдаётся запрошенная часть документа (см. "Range-Unit" в запросе клиента)

Коды с номером типа 3xx: перенаправление — действие нуждается в уточнении либо просто информационный ответ:

  • "300 Multiple Choices" — множественный выбор — по данному запросу обнаружено несколько вариантов документов
  • "301 Moved Permanently" — документ переехал
  • "302 Found" — найдено
  • "303 See Other" — смотри остальные
  • "304 Not Modified" — не изменён
  • "305 Use Proxy" — используй прокси
  • "307 Section" — временное перемещение запроса

Коды с номером типа 4xx: ошибка клиента — запрос клиента имеет либо неправильный синтаксис, либо не понят:

  • "400 Bad Request" — плохой запрос
  • "401 Unauthorized" — нет авторизации
  • "402 Payment Required" — коммерческий ресурс, у вас нет денег на счету
  • "403 Forbidden" — запрещение доступа к ресурсу (политика безопасности)
  • "404 Not Found" — ресурс не найден
  • "405 Method Not Allowed" — метод не поддерживается
  • "406 Not Acceptable" — нет доступа к хосту
  • "407 Proxy Authentication Required" — для работы с прокси вы должны авторизоваться
  • "408 Request Time-out" — слишком долго не было данных с сервера (связь плохая или сервер упал)
  • "409 Conflict" — конфликт
  • "410 Gone" — процесс идёт (не мешайте)
  • "411 Length Required" — требуется длина посылаемых данных
  • "412 Precondition Failed" — неправильные умолчания
  • "413 Request Entity Too Large" — содержимое запроса слишком велико для этого сервера
  • "414 Request-URI Too Large" — слишком длинный адрес запрашиваемого ресурса
  • "415 Unsupported Media Type" — в "Accept" не указан поддерживаемый сервером формат данных
  • "416 Requested range not satisfiable" — требуемый кусок (с помощью "Range-Unit") имеет неверные размеры
  • "417 Expectation Failed" — неожиданная ошибка при разборе запроса (может возникнуть при пересылке типа "multipart/form-data" при неправильном делителе)

Коды с номером типа 5xx: ошибка сервера — сервер не может обработать запрос клиента

  • "500 Internal Server Error" — внутренняя ошибка сервера
  • "501 Not Implemented" — не применяется (этот запрос не применим)
  • "502 Bad Gateway" — "плохие врата" — сервер не обрабатывает запросы с этого сегмента IP
  • "503 Service Unavailable" — такой сервис недоступен (к примеру TRACE запрос)
  • "504 Gateway Time-out" — слишком долго сервер пытался получить данные, связь плохая
  • "505 HTTP Version not supported" — версия HTTP, указанная в запросе, не поддерживается данным сервером

Параметры HTTP ответа

Продолжим разбор параметров заголовка в ответе сервера. Прежде всего упомяну, что параметры "Cache-Control", "Pragma" и "Proxy-Connection" идентичны как для запроса, так и для ответа, по этому всё сказанное про них выше, применимо и тут.

Set-Cookie: name=value; expires=date;
	path=PATH; domain=HOSTNAME; secure

Не буду подробно останавливаться на этом параметре. Он устанавливает или удаляет cookie и подробно о нём написано в Cookie Specification.

Location: http://www.devresource.org

Данный параметр указывает браузеру, что нужно открыть ресурс http://www.devresource.org вместо текущего. В значении этого параметра указывается URI ресурса для перехода.

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

Параметр показывает дату документа. Это либо текущая дата (если документ динамический), либо дата создания отправляемого файла. Дата представлена в формате GMT.

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

Параметр показывает дату последнего изменения документа.

Server: Apache/1.3.20 (Win32) PHP/4.3.0

Параметр содержит имя сервера.

Keep-Alive: timeout=15, max=100
Connection: Keep-Alive

Эти два параметра сообщают, что поддерживается постоянное соединение с сервером (вы противном случае было бы "Connection: close"), что текущее время timeout для сокета сервера составляет 15 секунд и что клиент может изменить это время максимум до 100 секунд.

Accept-Ranges: bytes

Этот параметр существует, чтобы указать клиенту, какая часть документа ему пересылается (в случае присутствия "Range-Unit" в запросе) Параметр этот может содержать значение "bytes", означающее, что пересылается файл целиком. Так же "none" (или этот параметр может быть просто опущен), означающее, что докачка не используется или не поддерживается, а строка "Accept-Ranges: 1:637" будет означать, что пересылается кусок документа с байта под номером 1 и длиной в 637 байт.

Content-Length: 673

Длина пересылаемого документа.

Content-Type: application/zip

MIME тип пересылаемого документа

Content-Disposition: attachment; filename=test.zip

указывает, что пересылаемый файл имеет название "test.zip"

Accept-Charset: windows-1251

указывает кодировку текста документа (в данном случае — русскую кодировку windows)

Accept-Encoding: compress, gzip

этот параметр используется сервером, чтобы указать клиенту, что документ ему передаётся в сжатом виде (и для сжатия используется стандарт gzip)

Accept-Language: ru

Параметр указывает на язык, использованный сервером для документа. IE6, получивший такой заголовок, к примеру, может переключить раскладку клавиатуры на русскую для текстовых элементов в полученном документе.

Transfer-Encoding: chunked

Данный параметр показывает метод выдачи данных сервером. В данном случае сервер будет выдавать данные по кусочкам, а не всё сразу.

На этом краткое описание HTTP протокола можно считать завершённым.




Справка | Условия Copyright © 1999 — 2010, IT • archiv.
В начало | Логин | Комментарий к колонке | Поиск | Почта