Java. HTTP протокол и работа с WEB
обратно | оглавление | далее
Протокол 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¶m2=2
Взглянув на пример, можно заметить, что запрос начинается со слова "POST". Это слово означает метод передачи данных на сервер, в котором дополнительные данные запроса (строка "param1=1¶m2=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¶m2=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¶m2=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/javalinks/catalog.php3?name=java&cat=2#section1
Из приведённого примера URL можно выделить логические части:
1) [http://] 2) [devresource.org/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¶m2=2 HTTP/1.1то сервер будет искать документ
http://localhost/localhost/?param1=1¶m2=2а не
http://localhost/?param1=1¶m2=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: информационный - запрос послан, идёт процесс:
Коды с номером типа 2xx: удачное завершение - запрос полностью послан, прочитан/понят сервером и принят им:
Коды с номером типа 3xx: перенаправление - действие нуждается в уточнении либо просто информационный ответ:
Коды с номером типа 4xx: ошибка клиента - запрос клиента имеет либо неправильный синтаксис, либо не понят:
Коды с номером типа 5xx: ошибка сервера - сервер не может обработать запрос клиента
Параметры 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/zipMIME тип пересылаемого документа
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 протокола можно считать завершённым.
обратно | оглавление | далее