HTTP Кратко: HTTP-сообщения
Russian (Pусский) translation by Dima (you can also view the original English article)
В этой главе мы рассмотрим сообщения, обменянные в транзакции HTTP. Мы узнаем о типах сообщений, заголовках HTTP и кодах состояния. Понимание того, что находится внутри HTTP-сообщения, жизненно важно для разработчиков, которые работают в Интернете. Вы не только создадите лучшие приложения, ответив нужными типами сообщений, но также сможете обнаружить проблемы с отладкой, если веб-приложения не работают.
Запросы и ответы
Представьте, что вы идете к незнакомцу в аэропорту и спрашиваете: «Знаете ли вы сколько время?» Для того, чтобы незнакомец ответил на правильное время, нужно сделать несколько вещей. Во-первых незнакомец должен понять ваш вопрос, потому что если он или она не знает английского, он или она не сможет ответить. Во-вторых, незнакомому человеку потребуется доступ к часам или другому устройству для просмотра времени.
Эта аналогия аэропорта похожа на работу HTTP. Вам, клиенту, нужен ресурс от какой-то другой стороны (ресурс - это информация о времени суток). Таким образом, вы делаете запрос другой стороне, используя язык и словарный запас, который, как вы надеетесь, понимает другая сторона. Если другая сторона понимает ваш запрос и имеет доступный ресурс, он может ответить. Если он понимает запрос, но не имеет ресурса, он все равно может ответить и сказать, что он не знает. Если другая сторона не понимает, что вы говорите, вы можете не получить никакого ответа.
HTTP - это протокол запроса и ответа. Клиент отправляет HTTP-запрос серверу с использованием тщательно отформатированного сообщения, которое сервер будет понимать. Сервер отвечает путем отправки HTTP-ответа, который клиент будет понимать. Запрос и ответ - это два разных типа сообщений, которые обмениваются в одной транзакции HTTP. Стандарты HTTP определяют, что входит в эти сообщения запроса и ответа, чтобы все, кто говорит «HTTP», понимали друг друга и могли обмениваться ресурсами (или когда ресурс не существует, сервер все равно может ответить и сообщить вам).
Необработанный запрос и ответ
Веб-браузер знает, как отправить HTTP-запрос, открыв сетевое подключение к серверной машине и отправив HTTP-сообщение в виде текста. В запросе нет ничего волшебного - это просто команда в текстовом ASCII-тексте и отформатирована в соответствии со спецификацией HTTP. Любое приложение, которое может отправлять данные по сети, может выполнить HTTP-запрос. Вы даже можете сделать запрос вручную с помощью приложения, такого как Telnet, из командной строки. Обычный сеанс Telnet подключается через порт 23, но, как мы узнали в первой главе, стандартным сетевым портом для HTTP является порт 80.
На следующем рисунке показан скриншот сеанса Telnet, который подключается к odetocode.com на порту 80, выполняет HTTP-запрос и получает ответ HTTP.



Сеанс Telnet начинается с ввода:
telnet www.odetocode.com 80
Обратите внимание, что клиент Telnet по умолчанию не установлен в Windows 7, Windows Server 2008 R2, Windows Vista или Windows Server 2008. Вы можете установить клиент, выполнив процедуру, указанную по адресу http://technet.microsoft.com/en-us/library/cc771275(v=ws.10).aspx.
Эта команда сообщает операционной системе запустить приложение Telnet и сообщает приложению Telnet подключиться к www.odetocode.com на порту 80.
После подключения Telnet мы можем ввести сообщение HTTP-запроса. Первая строка создается, введя следующий текст и нажав Enter:
GET / HTTP/1.1
Эта информация сообщит серверу, что мы хотим получить ресурс, расположенный в «/» (т. е. корневой ресурс или домашняя страница), и мы будем использовать функции HTTP 1.1. Следующая строка, которую мы вводим:
host:www.odetocode.com
Эта информация хоста является необходимой частью информации в сообщении запроса HTTP 1.1. Техническая причина для этого - помочь серверам, поддерживающим несколько веб-сайтов, то есть как на www.odetocode.com, так и на www.odetofood.com можно разместить на одном сервере, а информация о хосте в сообщении поможет веб-серверу запрос на правильное веб-приложение.
После ввода двух предыдущих строк мы можем дважды нажать Enter, чтобы отправить сообщение на сервер. Что вы видите далее в окне Telnet является HTTP-ответ от веб-сервера. Мы рассмотрим более подробные сведения позже, но в ответе говорится, что ресурс, который мы хотим (домашняя страница по умолчанию на www.odetocode.com), переместился. Он переместился на сайт odetocode.com. Теперь клиент должен проанализировать это ответное сообщение и отправить запрос на odetocode.com вместо www.odetocode.com, если он хочет получить домашнюю страницу. Любой веб-браузер автоматически перейдет в новое место.
Эти типы «перенаправления» являются общими, и в этом случае причина заключается в том, чтобы убедиться, что все запросы ресурсов из OdeToCode проходят через odetocode.com, а не www.odetocode.com (это оптимизация поисковой системы, известная как канонизация URL) ,
Теперь, когда мы увидели необработанный HTTP-запрос и ответ, давайте займемся определенными частями.
Методы запроса HTTP
Слово GET
, введенное в сеанс Telnet, является одним из основных методов HTTP. Каждое сообщение запроса должно включать один из HTTP-методов, и метод сообщает серверу, что запрос хочет сделать. HTTP GET
хочет получить, выбрать и извлечь ресурс. Вы могли бы GET
изображение (GET /logo.png
), или GET
файл PDF (GET /documents/report.pdf
) или любой другой извлекаемый ресурс, который может хранить сервер. Список общих HTTP-операторов показан в следующей таблице.
Метод | Описание |
Получить | Извлечение ресурса |
ПОЛОЖИТЕ | Хранить ресурс |
УДАЛИТЬ | Удалить ресурс |
Поместить | Обновить ресурс |
РУКОВОДИТЕЛЬ | Получить заголовки для ресурса |
Из этих пяти методов только два являются основными рабочими лошадками сети: GET
и POST
. Веб-браузер выдает запрос GET
, когда он хочет получить ресурс, например страницу, изображение, видео или документ. Запросы GET
являются наиболее распространенным типом запроса.
Веб-браузер отправляет запрос POST
, когда у него есть данные для отправки на сервер. Например, нажав «Добавить в корзину» на сайте, например amazon.com, вы получите сообщение POST
в Amazon о том, что мы хотим приобрести. POST
запросы обычно генерируются<form>
на веб-странице как форма вы заполнить с<input>
элементы адреса и данные кредитной карты.
GET и безопасность
Существует часть спецификации HTTP, которая говорит о «безопасных» методах HTTP. Безопасные методы, как следует из названия, не делают ничего «небезопасного», например, уничтожают ресурс, отправляют транзакцию по кредитной карте или отменяют учетную запись. Метод GET
является одним из безопасных методов, поскольку он должен только извлекать ресурс, а не изменять состояние ресурса. Отправка запроса GET
для изображения JPG не изменяет изображение, оно только выбирает изображение для отображения. Короче говоря, никогда не должно быть побочного эффекта для запроса GET
.
HTTP POST
не является безопасным методом. POST
обычно что-то изменяет на сервере - он обновляет учетную запись, отправляет заказ или выполняет другую специальную операцию. Веб-браузеры обычно обрабатывают GET
и POST
иначе, так как GET
безопасен, а POST
небезопасен. Это нормально обновить веб-страницу, полученную с помощью запроса GET
- веб-браузер просто переиздает последний запрос GET
и отобразит все, что сервер отправит обратно. Однако, если страница, которую мы просматриваем в браузере, является ответом HTTP POST
-запроса, браузер предупредит нас, если мы попытаемся обновить страницу. Возможно, вы видели эти типы предупреждений в веб-браузере.

Из-за таких предупреждений многие веб-приложения всегда стараются оставить клиента просмотра результата запроса GET
. После того, как пользователь нажимает кнопку на POST
-информацию на сервер (например, отправляет заказ), сервер обрабатывает информацию и отвечает перенаправлением HTTP (например, перенаправление, которое мы видели в окне Telnet), сообщающее браузеру GET
какой-либо другой ресурс. Браузер выдаст запрос GET
, сервер ответит ресурсом «спасибо за заказ», а затем пользователь сможет обновить или распечатать страницу безопасно столько раз, сколько захочет. Это общий шаблон веб-дизайна, известный как шаблон POST
/Redirect/GET
.
Теперь, когда мы знаем немного больше о POST
и GET
, давайте поговорим о некоторых распространенных сценариях и посмотрим, когда использовать разные методы.
Общие сценарии GET
Предположим, у вас есть страница и вы хотите, чтобы пользователь щелкнул ссылку, чтобы просмотреть первую статью этой серии. В этом случае простая гиперссылка - это все, что вам нужно.
<a href="http://odetocode.com/Articles/741.aspx">Part I</a>
Когда пользователь нажимает на гиперссылку в браузере, браузер выдает запрос GET
на URL, указанный в атрибуте href
теги привязки. Вот так будет выглядеть запрос:
GET http://odetocode.com/Articles/741.aspx HTTP/1.1 Host: odetocode.com
Сценарий POST
Теперь представьте, что у вас есть страница, где пользователь должен заполнить информацию для создания учетной записи. Для заполнения информации требуются теги<input>
Эти входные данные мы вставляем в<form>
и указываем браузеру, куда отправить информацию.
<form action="/account/create" method="POST"> <label for="firstName">First name</label> <input id="firstName" name="firstName" type="text" /> <label for="lastName">Last name</label> <input id="lastName" name="lastName" type="text" /> <input type="submit" value="Sign up!"/> </form>
Когда пользователь нажимает кнопку отправки, браузер понимает, что кнопка находится внутри формы. Форма сообщает браузеру, что HTTP-метод для использования - POST
, а путь к POST
- /account/create
. Фактический HTTP-запрос, который делает браузер, будет выглядеть примерно так.
POST http://localhost:1060/account/create HTTP/1.1 Host: server.com firstName=Scott&lastName=Allen
Обратите внимание, что входные данные формы включены в сообщение HTTP. Это очень похоже на то, как параметры отображаются в URL-адресе, как мы видели в предыдущей статье. Это зависит от веб-приложения, которое получает этот запрос для анализа этих значений и создания учетной записи пользователя. Затем приложение может ответить любым количеством способов, но есть три общих ответа:
- Ответьте с помощью HTML, указав пользователю, что учетная запись создана. Это приведет к тому, что пользователь просмотрит результат запроса
POST
, что может привести к проблемам, если он или она обновит страницу - возможно, он попытается подписать их во второй раз! - Ответьте с помощью команды перенаправления, как мы видели ранее, чтобы браузер выдал безопасный запрос
GET
для страницы, которая сообщает пользователю, что учетная запись была создана. - Ответьте на ошибку с ошибкой или перейдите на страницу с ошибкой. Мы рассмотрим сценарии ошибок чуть позже в книге.
Формы и запросы GET
Третий сценарий является сценарий поиска. В сценарии поиска вам нужен<input
>для пользователя, чтобы ввести поисковый запрос. Это может выглядеть следующим образом.
<form action="/search" method="GET"> <label for="term">Search:</label> <input id="term" name="term" type="text" /> <input type="submit" value="Sign up!"/> </form>
Обратите внимание, что метод в этой форме GET
, а не POST
. Это потому, что поиск - это операция безопасного извлечения, в отличие от создания учетной записи или бронирования рейса в Бельгию. Браузер будет собирать входные данные в форме и выдавать запрос GET
серверу:
GET http://localhost:1060/search?term=love HTTP/1.1 Host: searchengine.com
Обратите внимание, что вместо ввода входных значений в тело сообщения входные данные входят в часть строки запроса URL-адреса. Браузер отправляет запрос GET
для /search?Term = love
. Поскольку поисковый запрос находится в URL-адресе, пользователь может пометить URL-адрес или скопировать ссылку и отправить ее по электронной почте. Пользователь также может обновлять страницу столько раз, сколько захочет, потому что операция GET
для результатов поиска - это безопасная операция, которая не будет уничтожать или изменять данные.
Слово о методах и ресурсах
Мы довольно много говорили о ресурсах как о физических ресурсах в файловой системе сервера. Довольно часто такие ресурсы, как файлы PDF, видеофайлы, файлы изображений и файлы сценариев, существуют как физические файлы на сервере. Однако URL-адреса, указывающие внутри многих современных веб-приложений, действительно не указывают на файлы. Такие технологии, как ASP.NET и Ruby on Rails, перехватят запрос на ресурс и ответят, как они считают нужным. Они могут читать файл из базы данных и возвращать содержимое в ответе HTTP, чтобы оно выглядело так, как будто этот ресурс действительно существовал на самом сервере.
Хорошим примером является пример POST
, который мы использовали ранее, что привело к запросу /account/create
. Скорее всего, нет реального файла с именем «create» в каталоге «account». Вместо этого что-то на веб-сервере подбирает этот запрос, считывает и проверяет информацию пользователя и создает запись в базе данных. Ресурс /account/create
является виртуальным и не существует. Однако, чем больше вы можете думать о виртуальном ресурсе как о реальном ресурсе, тем лучше ваша архитектура и дизайн приложений будут соответствовать сторонам HTTP.
Заголовки HTTP запроса
До сих пор мы видели необработанный HTTP-запрос и говорили о двух популярных HTTP-методах - GET
и POST
. Но, как показал вывод Telnet, сообщение HTTP-запроса больше, чем HTTP-метод. Полное сообщение HTTP-запроса состоит из следующих частей:
[method] [URL] [version] [headers] [body]
Сообщение всегда находится в тексте ASCII, и в строке начала всегда содержатся метод, URL-адрес и версия HTTP (чаще всего это 1.1, который существует с 1999 года). Последний раздел, раздел тела, может содержать данные, такие как параметры входа в учетную запись, которые мы видели ранее. При загрузке файла часть тела может быть довольно большой.
Средний раздел, раздел, где мы видели Host: odetocode.com
, содержит один или несколько HTTP-заголовков (помните, что в HTTP 1.1 host
является обязательным заголовком). Заголовки содержат полезную информацию, которая может помочь серверу обработать запрос. Например, в последней статье мы говорили о представлениях ресурсов и о том, как клиент и сервер могут вести переговоры о наилучшем представлении ресурса (согласование контента). Например, если клиент хочет увидеть ресурс на французском языке, он может включать заголовок (заголовок Accept-Language
), запрашивающий французский контент.
GET http://odetocode.com/Articles/741.aspx HTTP/1.1 Host: odetocode.com Accept-Language: fr-FR
Существует множество заголовков, определенных спецификацией HTTP. Некоторые заголовки представляют собой общие заголовки, которые могут отображаться либо в запросе, либо в ответном сообщении. Примером может служить заголовок Date
. Клиент или сервер могут включать заголовок Date
, указывающий, когда он создал сообщение.
GET http://odetocode.com/Articles/741.aspx HTTP/1.1 Host: odetocode.com Accept-Language: fr-FR Date: Fri, 9 Aug 2002 21:12:00 GMT
Все, кроме заголовка узла, необязательно, но когда заголовок появляется, он должен соблюдать стандарты. Например, в спецификации HTTP указано, что значение заголовка даты должно быть в формате RFC822 для дат.
Некоторые из наиболее популярных заголовков запросов представлены в следующей таблице.
Заголовок | Описание |
Referer | Когда пользователь нажимает на ссылку, клиент может отправить URL-адрес ссылочной страницы в этот заголовок. |
Агент пользователя | Информация о пользовательском агенте (программном обеспечении), подающем запрос. Многие приложения используют информацию в этом заголовке, если она есть, для определения того, что браузер делает запрос (Internet Explorer 6 против Internet Explorer 9 по сравнению с Chrome и т. д.). |
Принять | Описывает типы носителей, которые пользовательский агент готов принять. Этот заголовок используется для согласования содержимого. |
Принимать язык | Описывает языки, которые предпочитает пользовательский агент. |
Cookie | Содержит информацию о файлах cookie, о которых мы расскажем в следующей главе. Информация о файлах cookie обычно помогает отслеживать сервер или идентифицировать пользователя. |
If-Modified-Since | Будет содержать дату, когда агент пользователя в последний раз извлекал (и кэшировал) ресурс. Серверу только нужно отправить обратно весь ресурс, если он был изменен с того времени. |
Полный HTTP-запрос может выглядеть следующим образом.
GET http://odetocode.com/ HTTP/1.1 Host: odetocode.com Connection: keep-alive User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) Chrome/16.0.912.75 Safari/535.7 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Referer: http://www.google.com/url?&q=odetocode Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Как вы можете видеть, некоторые заголовки содержат несколько значений, например заголовок Accept
. Заголовок Accept
содержит список типов MIME, которые он любит видеть, включая HTML, XHTML, XML и, наконец, * / * (это означает, что я лучше всего использую HTML, но вы можете отправить мне что-нибудь (* / *), и я попытаюсь выясните это).
Также обратите внимание на появление «q
» в некоторых заголовках. Значение q
всегда является числом от 0 до 1 и представляет значение качества или «относительную степень предпочтения» для определенного значения. Значение по умолчанию - 1,0, а более высокие номера - более предпочтительны.
Ответ
Ответ HTTP похож на HTTP-запрос. Секции ответа:
[version] [status] [reason] [headers] [body]
Полный HTTP-ответ на последний полный запрос, который мы указали, может выглядеть так (с большей частью HTML опущен для краткости).
HTTP/1.1 200 OK Cache-Control: private Content-Type: text/html; charset=utf-8 Server: Microsoft-IIS/7.0 X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET Date: Sat, 14 Jan 2012 04:00:08 GMT Connection: close Content-Length: 17151 <html> <head> <title>.NET-related Articles, Code and Resources</title> </head> <body> ... content ... </body> </html>
Начальная строка запроса начинается с версии HTTP, а затем код важного состояния и причины.
Коды состояния ответа
Код состояния - это число, определенное спецификацией HTTP, и все числа попадают в одну из пяти категорий.
Диапазон | Категория |
100-199 | Информационные |
200-299 | Успешные |
300-399 | Перенаправление |
400-499 | Ошибка клиента |
500-599 | Ошибка сервера |
Хотя мы не будем подробно описывать все возможные коды состояния HTTP, в следующей таблице будут подробно описаны наиболее распространенные коды.
Код | Причина | Описание |
200 | Хорошо | Код статуса, который все хотят видеть. Код 200 в ответе означает, что все сработало! |
301 | Перемещен навсегда | Ресурс переместился на URL-адрес, указанный в заголовке Location , и клиенту никогда не нужно снова проверять этот URL.Мы видели пример этого ранее, когда мы использовали Telnet, и сервер перенаправил нас с сайта www.odetocode.com на odetocode.com, чтобы дать поисковым системам канонический URL-адрес. |
302 | Временно перемещен | Ресурс переместился на URL, указанный в заголовке Location . В будущем клиент может запросить URL-адрес, поскольку это временный ход.Этот тип кода ответа обычно используется после операции POST для перемещения клиента на ресурс, который он может получить с помощью GET (шаблон POST / Redirect/GET , о котором мы говорили ранее). |
304 | Не изменено | Это сервер, сообщающий клиенту, что ресурс не изменился с момента последнего получения клиентом ресурса, поэтому он может просто использовать локально кэшированную копию. |
400 | Неправильный запрос | Сервер не может понять запрос. Вероятно, запрос использовал неправильный синтаксис. |
403 | Запрещено | Сервер отказал в доступе к ресурсу. |
404 | Не обнаружено | Популярный код, означающий, что ресурс не найден. |
500 | Внутренняя ошибка сервера | На сервере возникла ошибка при обработке запроса. Обычно происходит из-за ошибок программирования в веб-приложении. |
503 | Сервис недоступен | В настоящий момент сервер не будет обслуживать запрос. Этот код состояния может появляться, когда сервер обрабатывает запросы, поскольку он находится под большой нагрузкой. |
Коды статуса ответа являются чрезвычайно важной частью HTTP-сообщения, потому что они сообщают клиенту, что произошло (или в случае перенаправления, куда идти дальше).
Коды состояния HTTP в сравнении с вашим приложением
Помните, что код состояния HTTP - это код, указывающий, что происходит на уровне HTTP. Это не обязательно отражает то, что произошло внутри вашей заявки. Например, представьте, что пользователь отправляет на сервер форму входа в систему, но не заполняет поле «Фамилия». Если вашему приложению требуется фамилия, он не сможет создать учетную запись для пользователя. Это не означает, что вам нужно вернуть код ошибки HTTP, указывающий на сбой. Вероятно, вам нужно совсем другое - вы хотите успешно вернуть некоторый контент клиенту с кодом состояния 200 (OK). Содержимое сообщит пользователю, что фамилия не указана. С точки зрения приложения запрос был неудачным, но с точки зрения HTTP запрос был успешно обработан. Это нормально в веб-приложениях.
Заголовки ответов
Ответ включает информацию заголовка, которая дает метаданные клиента, которые она может использовать для обработки ответа. Например, тип содержимого будет указываться как тип MIME, о котором мы говорили в последней статье. В следующем ответе мы видим, что тип содержимого - HTML, а набор символов, используемый для кодирования типа, - UTF-8. Заголовки могут также содержать информацию о сервере, например имя программного обеспечения и версию.
HTTP/1.1 200 OK Cache-Control: private Content-Type: text/html; charset=utf-8 Server: Microsoft-IIS/7.0 X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET Date: Sat, 14 Jan 2012 04:00:08 GMT Connection: close Content-Length: 17151 <html> <head> <title>.NET-related Articles, Code and Resources</title> </head> <body> ... content ... </body> </html>
Заголовки ответов, которые появляются, часто зависят от типа ответа. Например, ответ перенаправления должен включать заголовок Location
, который сообщает клиенту, куда идти дальше.
Существует ряд заголовков, посвященных кешированию и оптимизации производительности. ETag
, Expires
и Last-Modified
предоставляют информацию о кешируемости ответа. ETag
- это идентификатор, который изменится при изменении основного ресурса, поэтому сравнение ETag
s - эффективный способ узнать, нужно ли что-то обновлять. Заголовок Expires
сообщает клиенту, как долго кэшировать определенный ресурс. Мы вернемся и посмотрим на кеширование более подробно позже.
Где мы?
В этой главе мы узнали, что HTTP-сообщения всегда попадают парами. Сначала есть запрос, а затем есть ответ. Информация в этих сообщениях доступна в читаемом тексте, и есть множество инструментов, которые вы можете использовать для проверки HTTP-запросов, сделанных на вашем компьютере. Fiddler - один из таких инструментов, если вы используете Windows (http://fiddler2.com). Он прост в использовании, и вы можете видеть необработанные HTTP-запросы, включая все заголовки.
Все сообщения касаются того, чтобы обе стороны в транзакции понимали, что они получают. Первая строка HTTP-сообщения всегда четко указывает на ее намерение. В сообщении с запросом сначала указывается URL-адрес и метод HTTP, чтобы определить, что должно произойти с конкретным ресурсом. В ответе код состояния укажет, как был обработан запрос. У нас также есть заголовки, движущиеся в обоих направлениях, которые предоставляют еще больше информации о запросе и ответе. В следующей главе мы узнаем немного больше о том, как эти сообщения перемещаются по сети.