GrabDuck

Java. HTTP протокол и работа с WEB

:


обратно | оглавление | далее

Протокол 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 протокола можно считать завершённым.


обратно | оглавление | далее