В этой главе мы рассмотрим сообщения, которыми обмениваются в транзакции 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 начинается с ввода:
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-запроса. Первая строка создается путем ввода следующего текста и нажатия клавиши « Ввод» :
GET / HTTP / 1.1
Эта информация сообщит серверу, что мы хотим получить ресурс, расположенный в «/» (т. Е. Корневой ресурс или домашнюю страницу), и мы будем использовать функции HTTP 1.1. Следующая строка, которую мы вводим:
хост: 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, вы отправите в Amazon информацию о том, что мы хотим приобрести. POST
запросы обычно генерируются <form>
на веб-странице, например, форма, которую вы заполняете элементами <input>
для адреса и информации о кредитной карте.
ПОЛУЧИТЬ и Безопасность
Есть часть спецификации 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
Допустим, у вас есть страница и вы хотите, чтобы пользователь щелкнул ссылку для просмотра первой статьи в этой серии. В этом случае простая гиперссылка — это все, что вам нужно.
1
|
<a href=»http://odetocode.com/Articles/741.aspx»>Part I</a>
|
Когда пользователь щелкает гиперссылку в браузере, браузер GET
запрос GET
на URL-адрес, указанный в атрибуте href
тега привязки. Запрос будет выглядеть так:
ПОЛУЧИТЬ http://odetocode.com/Articles/741.aspx HTTP / 1.1 Хост: odetocode.com
Сценарий-POST
Теперь представьте, что у вас есть страница, где пользователь должен заполнить информацию, чтобы создать учетную запись. Для заполнения информации требуются теги <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-запрос, который делает браузер, будет выглядеть примерно так.
POST http: // localhost: 1060 / account / create HTTP / 1.1 Хост: server.com Firstname = Скотт & LastName = Аллен
Обратите внимание, что входные данные формы включены в сообщение HTTP. Это очень похоже на то, как параметры появляются в URL, как мы видели в предыдущей статье. Это веб-приложение, которое получает этот запрос, чтобы проанализировать эти значения и создать учетную запись пользователя. Затем приложение может ответить любым количеством способов, но есть три общих ответа:
- Ответьте с HTML, сообщая пользователю, что учетная запись была создана. В результате пользователь увидит результат запроса
POST
, что может привести к проблемам, если он или она обновит страницу — он может попытаться зарегистрировать их во второй раз! - Ответьте инструкцией по перенаправлению, как мы видели ранее, чтобы браузер выдал безопасный
GET
для страницы, которая сообщает пользователю, что учетная запись была создана. - Ответить с ошибкой или перенаправить на страницу ошибки. Мы рассмотрим сценарии ошибок чуть позже в книге.
Формы и GET-запросы
Третий сценарий — это сценарий поиска. В сценарии поиска пользователю требуется <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
запрос на сервер:
ПОЛУЧИТЕ http: // localhost: 1060 / search? Term = love HTTP / 1.1 Ведущий: searchengine.com
Обратите внимание, что вместо помещения входных значений в тело сообщения, входные данные идут в часть строки запроса 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-запрос и говорили о двух популярных HTTP-методах — GET
и POST
. Но, как показал вывод Telnet, в запросе HTTP есть нечто большее, чем просто метод HTTP. Сообщение полного HTTP-запроса состоит из следующих частей:
[метод] [URL] [версия] [заголовки] [Тела]
Сообщение всегда находится в тексте ASCII, а строка начала всегда содержит метод, URL-адрес и версию HTTP (чаще всего 1.1, которая существует с 1999 года). Последний раздел, раздел body, может содержать такие данные, как параметры входа в учетную запись, которые мы видели ранее. При загрузке файла раздел body может быть довольно большим.
Средний раздел, где мы видели Host: odetocode.com
, содержит один или несколько заголовков HTTP (помните, в HTTP 1.1 host
является обязательным заголовком). Заголовки содержат полезную информацию, которая может помочь серверу обработать запрос. Например, в прошлой статье мы говорили о представлениях ресурсов и о том, как клиент и сервер могут согласовывать наилучшее представление ресурса (согласование контента). Если клиент хочет видеть ресурс на французском языке, например, он может включать в себя запись заголовка (заголовок Accept-Language
), запрашивающую французский контент.
ПОЛУЧИТЬ http://odetocode.com/Articles/741.aspx HTTP / 1.1 Хост: odetocode.com Accept-Language: fr-FR
Существует множество заголовков, определенных в спецификации HTTP. Некоторые из заголовков являются общими заголовками, которые могут появляться либо в запросе, либо в ответном сообщении. Примером является заголовок Date
. Клиент или сервер могут включать заголовок Date
указывающий, когда он создал сообщение.
ПОЛУЧИТЬ http://odetocode.com/Articles/741.aspx HTTP / 1.1 Хост: odetocode.com Accept-Language: fr-FR Дата: пт, 9 августа 2002 21:12:00 по Гринвичу
Все, кроме заголовка узла, является необязательным, но когда заголовок появляется, он должен соответствовать стандартам. Например, спецификация HTTP говорит, что значение заголовка даты должно быть в формате RFC822 для дат.
Некоторые из наиболее популярных заголовков запросов приведены в следующей таблице.
заголовок | Описание |
Referer | Когда пользователь нажимает на ссылку, клиент может отправить URL ссылающейся страницы в этом заголовке. |
User-Agent | Информация о пользовательском агенте (программном обеспечении), делающем запрос. Многие приложения используют информацию в этом заголовке, если она присутствует, чтобы выяснить, какой браузер делает запрос (Internet Explorer 6 против Internet Explorer 9 против Chrome и т. Д.). |
принимать | Описывает типы носителей, которые пользовательский агент готов принять. Этот заголовок используется для согласования содержимого. |
Accept-Language | Описывает языки, которые предпочитает пользовательский агент. |
печенье | Содержит информацию о файлах cookie, которые мы рассмотрим в следующей главе. Информация о файлах cookie обычно помогает серверу отслеживать или идентифицировать пользователя. |
If-Modified-Since | Будет содержать дату, когда пользовательский агент последний раз получал (и кэшировал) ресурс. Сервер должен отправить обратно весь ресурс, только если он был изменен с того времени. |
Полный HTTP-запрос может выглядеть следующим образом.
GET http://odetocode.com/ HTTP / 1.1 Хост: odetocode.com Подключение: keep-alive Пользователь-агент: Mozilla / 5.0 (Windows NT 6.1; WOW64) Chrome / 16.0.912.75 Safari / 535.7 Принять: текст / html, приложение / xhtml + xml, приложение / xml; q = 0,9, * / *; q = 0,8 Реферер: 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-запросу. Разделы ответа:
[версия] [статус] [причина] [заголовки] [Тела]
Полный HTTP-ответ на последний полный запрос, который мы перечислили, может выглядеть так (большая часть HTML опущена для краткости).
HTTP / 1.1 200 ОК Cache-Control: приватный Content-Type: text / html; кодировка = UTF-8 Сервер: Microsoft-IIS / 7.0 X-AspNet-версия: 2.0.50727 X-Powered-By: ASP.NET Дата: сб, 14 января 2012 04:00:08 GMT Подключение: закрыть Длина контента: 17151 <HTML> <Голова> <title> Статьи, код и ресурсы, связанные с .NET </ title> </ HEAD> <Тело> ... содержание ... </ Body> </ 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, потому что это временное перемещение.
Этот тип кода ответа обычно используется после операции |
304 | Не модифицировано | Этот сервер сообщает клиенту, что ресурс не изменился с момента последнего получения клиентом ресурса, поэтому он может просто использовать локально кэшированную копию. |
400 | Неверный запрос | Сервер не может понять запрос. Запрос, вероятно, использовал неправильный синтаксис. |
403 | запрещено | Сервер отказал в доступе к ресурсу. |
404 | не обнаружена | Популярный код, означающий, что ресурс не найден. |
500 | Внутренняя Ошибка Сервера | Сервер обнаружил ошибку при обработке запроса. Обычно происходит из-за ошибок программирования в веб-приложении. |
503 | Сервис недоступен | В настоящее время сервер не будет обслуживать запрос. Этот код состояния может появляться, когда сервер регулирует запросы, потому что он находится под большой нагрузкой. |
Коды состояния ответа являются невероятно важной частью HTTP-сообщения, потому что они сообщают клиенту, что произошло (или в случае перенаправления, куда идти дальше).
Коды состояния HTTP по сравнению с вашим приложением
Помните, что код состояния HTTP — это код, указывающий, что происходит на уровне HTTP. Это не обязательно отражает то, что произошло внутри вашего приложения. Например, представьте, что пользователь отправляет форму входа на сервер, но не заполняет поле Фамилия. Если вашему приложению требуется фамилия, оно не сможет создать учетную запись для пользователя. Это не означает, что вы должны вернуть код ошибки HTTP, указывающий на ошибку. Вы, вероятно, хотите, чтобы произошло совершенно противоположное — вы хотите успешно вернуть некоторый контент клиенту с кодом состояния 200 (ОК). Содержание сообщит пользователю, что фамилия не была предоставлена. С точки зрения приложения запрос был неудачным, но с точки зрения HTTP запрос был успешно обработан. Это нормально в веб-приложениях.
Заголовки ответа
Ответ включает информацию заголовка, которая предоставляет клиентские метаданные, которые он может использовать для обработки ответа. Например, тип контента будет указан как тип MIME, как мы говорили в прошлой статье. В следующем ответе мы видим, что тип содержимого — HTML, а набор символов, используемый для кодирования типа — UTF-8. Заголовки также могут содержать информацию о сервере, например, название программного обеспечения и версию.
HTTP / 1.1 200 ОК Cache-Control: приватный Content-Type: text / html; кодировка = UTF-8 Сервер: Microsoft-IIS / 7.0 X-AspNet-версия: 2.0.50727 X-Powered-By: ASP.NET Дата: сб, 14 января 2012 04:00:08 GMT Подключение: закрыть Длина контента: 17151 <HTML> <Голова> <title> Статьи, код и ресурсы, связанные с .NET </ title> </ HEAD> <Тело> ... содержание ... </ Body> </ Html>
Заголовки ответов, которые появляются, часто зависят от типа ответа. Например, ответ на перенаправление должен включать заголовок Location
который сообщает клиенту, куда идти дальше.
Существует ряд заголовков, посвященных кешированию и оптимизации производительности. ETag
, Expires
и Last-Modified
предоставляют информацию о возможности кэширования ответа. ETag
— это идентификатор, который будет меняться при изменении базового ресурса, поэтому сравнение ETag
— это эффективный способ узнать, нужно ли что-то обновлять. Заголовок Expires
сообщает клиенту, как долго следует кэшировать конкретный ресурс. Мы вернемся и рассмотрим кеширование более подробно позже.
Где мы?
В этой главе мы узнали, что HTTP-сообщения всегда приходят парами. Сначала идет запрос, а затем ответ. Вся информация в этих сообщениях читается в виде текста, и вы можете использовать множество инструментов для проверки HTTP-запросов, выполняемых на вашем компьютере. Fiddler является одним из таких инструментов, если вы работаете в Windows ( http://fiddler2.com ). Он прост в использовании, и вы можете видеть необработанные HTTP-запросы, включая все заголовки.
Все сообщения направлены на то, чтобы обе стороны в транзакции понимали, что они получают. В первой строке HTTP-сообщения всегда указывается его намерение. В сообщении с запросом сначала отображаются URL-адрес и метод HTTP, чтобы определить, что должно происходить с конкретным ресурсом. В ответе код состояния укажет, как был обработан запрос. У нас также есть заголовки, перемещающиеся в обоих направлениях, которые предоставляют еще больше информации о запросе и ответе. В следующей главе мы узнаем немного больше о том, как эти сообщения передаются по сети.