Классы HttpWebRequest и HttpWebResponse

147

Среда .NET Framework предоставляет два основных класса, облегчающих доступ к HTTP: HttpWebRequest и HttpWebResponse. В этих классах в простой форме реализована значительная часть функциональных возможностей, предоставляемых протоколом HTTP. Они порождены от абстрактных классов WebRequest и WebResponse.

Чтобы познакомиться с работой этих классов, давайте рассмотрим пример, как их можно использовать для получения страницы из Интернета:

string site = "http://www.professorweb.ru";

HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(site);
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();

using (StreamReader stream = new StreamReader(
     resp.GetResponseStream(), Encoding.UTF8))
{
     txb_text.Text = stream.ReadToEnd();
}

Для создания объекта HttpWebRequest нужно вызвать статический метод Create() класса WebRequest (также наследуемый классом HttpWebRequest). Этот метод исследует формат переданного ему URI и по обстановке возвращает объект WebRequest, представляющий HTTP-запрос или запрос к файловой системе. Поскольку один и тот же метод используется для создания как HTTP-запроса, так и запроса к файловой системе, возвращаемый объект имеет тип WebRequest и его нужно привести к типу HttpWebRequest или FileWebRequest. Метод Create() выполняет разбор URL и передает его в объект запроса. Затем блок запроса строит исходящий HTTP-запрос и также формирует конфигурацию HTTP-заголовков.

Получив объект запроса, можно вызвать для него метод GetResponse(). Этот метод отправляет запрос серверу и возвращает объект WebResponse (надо снова привести его к типу HttpWebResponse). Этот объект представляет сообщение HTTP-ответа и содержит информацию HTTP-заголовков, в том числе ContentType, ContentLength, StatusCode и Cookies, и первую часть данных, которые помещаются во внутренний буфер и должны быть считаны из потока. Вместе с данными устанавливаются свойства объекта HttpWebResponse.

Далее с помощью метода GetResponseStream() получаем поток. Он указывает на текущий ответ от Web-cepвepa (тело сути ответного сообщения) в двоичном виде. Поток предоставляет значительную гибкость в реализации способов получения данных от Web-cepвepa. Чтобы извлечь текущие данные и получить с Web-cepвepa оставшуюся часть результирующего документа, нужно считать этот поток. В данном примере используем объект StreamReader, возвращающий строку с данными. Для кодировки установлен тип UTF8. Кодировка — это важный момент, поскольку передача данных потоком байтов без перекодирования приведет к неверным преобразованиям всех расширенных символов.

В приведенном примере используется метод ReadToEnd() объекта StreamReader, считывающий в строку все данные с Web-cepвepa. Однако данные можно также считывать по частям, если применить метод Read() того же объекта.

Установка и считывание HTTP-заголовков

В обоих классах, HttpWebRequest и HttpWebResponse, есть свойство Headers, возвращающее объект WebHeaderCollection, содержащий информацию о заголовках HTTP-сообщения. Вызывая метод Add() или метод Set() этого объекта, можно добавлять заголовки в HTTP-запрос:

HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(site);
req.Headers.Add("Accept-Language: ru-ru");

Как показывает приведенный пример, метод Add() принимает один строковый параметр, представляющий все поле заголовка, тогда как метод Set() принимает два строковых значения: имя заголовка и значение, которое хотим в нем установить. Оба метода можно равным образом использовать для стандартных и специализированных HTTP-заголовков. Однако в классе HttpWebRequest также есть несколько открытых свойств, позволяющих установить заголовок запроса без обращения к свойству Headers:

Свойства класса HttpWebRequest для заголовков
Свойство Тип данных HTTP-заголовок
AcceptstringAccept
ConnectionstringConnection
ContentLengthlongContent-Length
ContentTypestringContent-Type
ExpectstringExpect
IfModifiedSinceDateTimeIf-Modified-Since
RefererstringReferer
TransferEncodingstringTransfer-Encoding
UserAgentstringUser-Agent

Например, чтобы сформировать заголовок User-Agent в виде "User-Agent: SimpleHttpClient", можно написать:

req.UserAgent = "SimpleHostClient";

Обратите внимание, что при наличии свойства установки заголовка следует обращаться именно к нему. Например, если попытаться установить заголовок User-Agent следующим образом:

req.Headers.Add("User-Agent: SimpleHostClient");

то при выполнении будет порождено исключение.

Объект HttpWebResponse также содержит несколько открытых свойств (все они доступны только на чтение), позволяющие обращаться к значениям выбранных HTTP-заголовков (ContentEncoding, ContentLength, ContentType, LastModified и Server).

К каждому отдельному полю заголовка также можно обратиться как к паре имя-значение в коллекции WebHeaderCollection. Имена заголовков являются ключами в коллекции, а значения заголовков — соответствующими значениями. Следовательно, можно обратиться к значению заголовка, используя в индексаторе коллекции имя заголовка. В следующем коде все заголовки ответа выводятся в текстовый элемент управления WPF:

foreach (string header in resp.Headers)
       txb_text.Text += String.Format("{0}: {1}\n", header, resp.Headers[header]);
Получение заголовков сервера
Лучший чат для C# программистов