Статьи

HTTP Succinctly: HTTP-сообщения

В этой главе мы рассмотрим сообщения, которыми обмениваются в транзакции 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-ответ.

Рисунок 2 Создание HTTP-запроса

Создание HTTP-запроса

Сеанс Telnet начинается с ввода:

1
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-запроса. Первая строка создается путем ввода следующего текста и нажатия клавиши « Ввод» :

Эта информация сообщит серверу, что мы хотим получить ресурс, расположенный в «/» (т. Е. Корневой ресурс или домашнюю страницу), и мы будем использовать функции HTTP 1.1. Следующая строка, которую мы вводим:

Эта информация о хосте является обязательной информацией в сообщении запроса 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-запрос и ответ, давайте разберемся с конкретными частями.


Слово GET введенное в сеанс Telnet, является одним из основных методов HTTP . Каждое сообщение с запросом должно содержать один из методов HTTP, и этот метод сообщает серверу, что хочет сделать запрос. HTTP GET хочет получить, получить и получить ресурс. Вы можете GET изображение ( GET /logo.png ) или GET PDF-файл ( GET /documents/report.pdf ) или любой другой извлекаемый ресурс, который может содержать сервер. Список общих операторов HTTP показан в следующей таблице.

метод Описание
ПОЛУЧИТЬ Получить ресурс
ПОЛОЖИЛ Хранить ресурс
УДАЛЯТЬ Удалить ресурс
ПОЧТА Обновить ресурс
ГОЛОВА Получить заголовки для ресурса

Из этих пяти методов только два являются основными рабочими лошадками в сети: GET и POST . Веб-браузер выдает запрос GET когда хочет получить ресурс, например страницу, изображение, видео или документ. GET запросы являются наиболее распространенным типом запросов.

Веб-браузер отправляет запрос POST когда у него есть данные для отправки на сервер. Например, нажав «Добавить в корзину» на таком сайте, как amazon.com, вы отправите в Amazon информацию о том, что мы хотим приобрести. POST запросы обычно генерируются <form> на веб-странице, например, форма, которую вы заполняете элементами <input> для адреса и информации о кредитной карте.


Есть часть спецификации HTTP, которая говорит о «безопасных» методах HTTP. Безопасные методы , как следует из названия, не делают ничего «небезопасного», например, уничтожают ресурс, отправляют транзакцию по кредитной карте или отменяют учетную запись. Метод GET является одним из безопасных методов, поскольку он должен только извлекать ресурс, а не изменять его состояние. Отправка запроса GET для изображения JPG не меняет изображение, оно только выбирает изображение для отображения. Короче говоря, никогда не должно быть побочных эффектов для запроса GET .

HTTP POST не является безопасным методом. POST обычно что-то меняет на сервере — обновляет учетную запись, отправляет заказ или выполняет какую-то другую специальную операцию. Веб-браузеры обычно обрабатывают GET и POST разному, поскольку GET безопасен, а POST небезопасен. Можно обновить веб-страницу, полученную с помощью запроса GET — веб-браузер просто перезапустит последний GET и отобразит все, что сервер отправит обратно. Однако, если страница, которую мы просматриваем в браузере, является ответом на запрос HTTP POST , браузер предупредит нас, если мы попытаемся обновить страницу. Возможно, вы видели подобные предупреждения в вашем веб-браузере.

Рисунок 3 Обновление запроса POST

Обновление POST-запроса

Из-за подобных предупреждений многие веб-приложения всегда пытаются оставить клиента, просматривающего результат запроса GET . После того, как пользователь нажимает кнопку для отправки информации POST на сервер (например, отправляя заказ), сервер обрабатывает информацию и отвечает перенаправлением HTTP (как перенаправление, которое мы видели в окне Telnet), сообщая браузеру GET какой-либо другой ресурс , Браузер выдаст запрос GET , сервер ответит ресурсом «спасибо за заказ», а затем пользователь сможет безопасно обновить или распечатать страницу столько раз, сколько он или она захочет. Это распространенный шаблон веб-дизайна, известный как шаблон POST / Redirect / GET .

Теперь, когда мы знаем немного больше о POST и GET , давайте поговорим о некоторых распространенных сценариях и посмотрим, когда использовать различные методы.


Допустим, у вас есть страница и вы хотите, чтобы пользователь щелкнул ссылку для просмотра первой статьи в этой серии. В этом случае простая гиперссылка — это все, что вам нужно.

1
<a href=»http://odetocode.com/Articles/741.aspx»>Part I</a>

Когда пользователь щелкает гиперссылку в браузере, браузер GET запрос GET на URL-адрес, указанный в атрибуте href тега привязки. Запрос будет выглядеть так:


Теперь представьте, что у вас есть страница, где пользователь должен заполнить информацию, чтобы создать учетную запись. Для заполнения информации требуются теги <input> , и мы вкладываем эти входные данные в <form> и сообщаем браузеру, куда отправить информацию.

01
02
03
04
05
06
07
08
09
10
11
<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-запрос, который делает браузер, будет выглядеть примерно так.

Обратите внимание, что входные данные формы включены в сообщение HTTP. Это очень похоже на то, как параметры появляются в URL, как мы видели в предыдущей статье. Это веб-приложение, которое получает этот запрос, чтобы проанализировать эти значения и создать учетную запись пользователя. Затем приложение может ответить любым количеством способов, но есть три общих ответа:

  1. Ответьте с HTML, сообщая пользователю, что учетная запись была создана. В результате пользователь увидит результат запроса POST , что может привести к проблемам, если он или она обновит страницу — он может попытаться зарегистрировать их во второй раз!
  2. Ответьте инструкцией по перенаправлению, как мы видели ранее, чтобы браузер выдал безопасный GET для страницы, которая сообщает пользователю, что учетная запись была создана.
  3. Ответить с ошибкой или перенаправить на страницу ошибки. Мы рассмотрим сценарии ошибок чуть позже в книге.

Третий сценарий — это сценарий поиска. В сценарии поиска пользователю требуется <input> для ввода поискового запроса. Это может выглядеть следующим образом.

1
2
3
4
5
6
7
<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 запрос на сервер:

Обратите внимание, что вместо помещения входных значений в тело сообщения, входные данные идут в часть строки запроса URL-адреса. Браузер отправляет запрос GET для /search?term=love . Поскольку поисковый термин содержится в URL, пользователь может добавить URL в закладки или скопировать ссылку и отправить ее по электронной почте. Пользователь также может обновлять страницу столько раз, сколько захочет, опять же, потому что операция GET для результатов поиска является безопасной операцией, которая не будет уничтожать или изменять данные.


Мы довольно много говорили о ресурсах как о физических ресурсах в файловой системе сервера. Довольно часто такие ресурсы, как файлы PDF, видеофайлы, файлы изображений и файлы сценариев , существуют как физические файлы на сервере. Однако URL-адреса, указывающие внутри многих современных веб-приложений, на самом деле не указывают на файлы. Такие технологии, как ASP.NET и Ruby on Rails, будут перехватывать запрос ресурса и отвечать так, как они считают нужным. Они могут прочитать файл из базы данных и вернуть содержимое HTTP-ответа, чтобы он выглядел так, как если бы ресурс действительно существовал на самом сервере.

Хорошим примером является пример POST мы использовали ранее, который привел к запросу /account/create . Скорее всего, в каталоге «account» нет реального файла с именем «create». Вместо этого что-то на веб-сервере получает этот запрос, считывает и проверяет информацию о пользователе и создает запись в базе данных. Ресурс /account/create является виртуальным и не существует. Однако чем больше вы можете рассматривать виртуальный ресурс как реальный ресурс, тем лучше архитектура и дизайн вашего приложения будут соответствовать сильным сторонам HTTP.


До сих пор мы видели необработанный HTTP-запрос и говорили о двух популярных HTTP-методах — GET и POST . Но, как показал вывод Telnet, в запросе HTTP есть нечто большее, чем просто метод HTTP. Сообщение полного HTTP-запроса состоит из следующих частей:

Сообщение всегда находится в тексте ASCII, а строка начала всегда содержит метод, URL-адрес и версию HTTP (чаще всего 1.1, которая существует с 1999 года). Последний раздел, раздел body, может содержать такие данные, как параметры входа в учетную запись, которые мы видели ранее. При загрузке файла раздел body может быть довольно большим.

Средний раздел, где мы видели Host: odetocode.com , содержит один или несколько заголовков HTTP (помните, в HTTP 1.1 host является обязательным заголовком). Заголовки содержат полезную информацию, которая может помочь серверу обработать запрос. Например, в прошлой статье мы говорили о представлениях ресурсов и о том, как клиент и сервер могут согласовывать наилучшее представление ресурса (согласование контента). Если клиент хочет видеть ресурс на французском языке, например, он может включать в себя запись заголовка (заголовок Accept-Language ), запрашивающую французский контент.

Существует множество заголовков, определенных в спецификации HTTP. Некоторые из заголовков являются общими заголовками, которые могут появляться либо в запросе, либо в ответном сообщении. Примером является заголовок Date . Клиент или сервер могут включать заголовок Date указывающий, когда он создал сообщение.

Все, кроме заголовка узла, является необязательным, но когда заголовок появляется, он должен соответствовать стандартам. Например, спецификация HTTP говорит, что значение заголовка даты должно быть в формате RFC822 для дат.

Некоторые из наиболее популярных заголовков запросов приведены в следующей таблице.

заголовок Описание
Referer Когда пользователь нажимает на ссылку, клиент может отправить URL ссылающейся страницы в этом заголовке.
User-Agent Информация о пользовательском агенте (программном обеспечении), делающем запрос. Многие приложения используют информацию в этом заголовке, если она присутствует, чтобы выяснить, какой браузер делает запрос (Internet Explorer 6 против Internet Explorer 9 против Chrome и т. Д.).
принимать Описывает типы носителей, которые пользовательский агент готов принять. Этот заголовок используется для согласования содержимого.
Accept-Language Описывает языки, которые предпочитает пользовательский агент.
печенье Содержит информацию о файлах cookie, которые мы рассмотрим в следующей главе. Информация о файлах cookie обычно помогает серверу отслеживать или идентифицировать пользователя.
If-Modified-Since Будет содержать дату, когда пользовательский агент последний раз получал (и кэшировал) ресурс. Сервер должен отправить обратно весь ресурс, только если он был изменен с того времени.

Полный HTTP-запрос может выглядеть следующим образом.

Как видите, некоторые заголовки содержат несколько значений, например заголовок Accept . Заголовок Accept содержит список типов MIME, которые он хочет видеть, включая HTML, XHTML, XML и, наконец, * / * (то есть, мне нравится HTML, но вы можете отправить мне что угодно (* / *), и я постараюсь разберись).

Также обратите внимание на появление « q » в некоторых заголовках. Значение q всегда является числом от 0 до 1 и представляет собой значение качества или «относительную степень предпочтения» для конкретного значения. По умолчанию используется значение 1,0, а более высокие числа указывают на более высокий приоритет.


HTTP-ответ имеет структуру, аналогичную HTTP-запросу. Разделы ответа:

Полный HTTP-ответ на последний полный запрос, который мы перечислили, может выглядеть так (большая часть HTML опущена для краткости).

Начальная строка запроса начинается с версии HTTP, а затем с важными кодом состояния и причиной.


Код состояния — это число, определяемое спецификацией HTTP, и все числа попадают в одну из пяти категорий.

Ассортимент категория
100-199 информационный
200-299 успешный
300-399 Перенаправление
400-499 Ошибка клиента
500-599 Ошибка сервера

Хотя мы не будем подробно описывать все возможные коды состояния HTTP, в следующей таблице приведены наиболее распространенные коды.

Код причина Описание
200 Ok Код статуса, который все хотят видеть. Код 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, указывающий на ошибку. Вы, вероятно, хотите, чтобы произошло совершенно противоположное — вы хотите успешно вернуть некоторый контент клиенту с кодом состояния 200 (ОК). Содержание сообщит пользователю, что фамилия не была предоставлена. С точки зрения приложения запрос был неудачным, но с точки зрения HTTP запрос был успешно обработан. Это нормально в веб-приложениях.


Ответ включает информацию заголовка, которая предоставляет клиентские метаданные, которые он может использовать для обработки ответа. Например, тип контента будет указан как тип MIME, как мы говорили в прошлой статье. В следующем ответе мы видим, что тип содержимого — HTML, а набор символов, используемый для кодирования типа — UTF-8. Заголовки также могут содержать информацию о сервере, например, название программного обеспечения и версию.

Заголовки ответов, которые появляются, часто зависят от типа ответа. Например, ответ на перенаправление должен включать заголовок Location который сообщает клиенту, куда идти дальше.

Существует ряд заголовков, посвященных кешированию и оптимизации производительности. ETag , Expires и Last-Modified предоставляют информацию о возможности кэширования ответа. ETag — это идентификатор, который будет меняться при изменении базового ресурса, поэтому сравнение ETag — это эффективный способ узнать, нужно ли что-то обновлять. Заголовок Expires сообщает клиенту, как долго следует кэшировать конкретный ресурс. Мы вернемся и рассмотрим кеширование более подробно позже.


В этой главе мы узнали, что HTTP-сообщения всегда приходят парами. Сначала идет запрос, а затем ответ. Вся информация в этих сообщениях читается в виде текста, и вы можете использовать множество инструментов для проверки HTTP-запросов, выполняемых на вашем компьютере. Fiddler является одним из таких инструментов, если вы работаете в Windows ( http://fiddler2.com ). Он прост в использовании, и вы можете видеть необработанные HTTP-запросы, включая все заголовки.

Все сообщения направлены на то, чтобы обе стороны в транзакции понимали, что они получают. В первой строке HTTP-сообщения всегда указывается его намерение. В сообщении с запросом сначала отображаются URL-адрес и метод HTTP, чтобы определить, что должно происходить с конкретным ресурсом. В ответе код состояния укажет, как был обработан запрос. У нас также есть заголовки, перемещающиеся в обоих направлениях, которые предоставляют еще больше информации о запросе и ответе. В следующей главе мы узнаем немного больше о том, как эти сообщения передаются по сети.