Обработчики сообщений HTTP в веб-API ASP.NET
Обработчик сообщений — это класс, который получает HTTP-запрос и возвращает HTTP-ответ. Обработчики сообщений являются производными от абстрактного класса HttpMessageHandler .
Как правило, ряд обработчиков сообщений объединяются в цепочку. Первый обработчик получает HTTP-запрос, выполняет некоторую обработку и передает запрос следующему обработчику. В какой-то момент создается ответ и возвращается вверх по цепочке. Этот шаблон называется делегированным обработчиком.

Обработчики сообщений Server-Side
На стороне сервера конвейер веб-API использует некоторые встроенные обработчики сообщений:
- HttpServer получает запрос от узла.
- HttpRoutingDispatcher отправляет запрос на основе маршрута.
- HttpControllerDispatcher отправляет запрос контроллеру веб-API.
В конвейер можно добавить пользовательские обработчики. Обработчики сообщений хорошо подходит для сквозных задач, которые работают на уровне HTTP-сообщений (а не действий контроллера). Например, обработчик сообщений может:
- Чтение или изменение заголовков запросов.
- Добавьте заголовок ответа в ответы.
- Проверяйте запросы, прежде чем они достигнут контроллера.
На этой схеме показаны два пользовательских обработчика, вставленных в конвейер:

На стороне клиента HttpClient также использует обработчики сообщений. Дополнительные сведения см. в разделе Обработчики сообщений HttpClient.
Пользовательские обработчики сообщений
Чтобы написать пользовательский обработчик сообщений, наследуйте от System.Net.Http.DelegatingHandler и переопределите метод SendAsync . Этот метод имеет следующую сигнатуру:
Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken);
Метод принимает HttpRequestMessage в качестве входных данных и асинхронно возвращает httpResponseMessage. Типичная реализация выполняет следующие действия:
- Обработайте сообщение запроса.
- Вызовите base.SendAsync , чтобы отправить запрос внутреннему обработчику.
- Внутренний обработчик возвращает ответное сообщение. (Этот шаг является асинхронным.)
- Обработайте ответ и верните его вызывающему объекту.
Ниже приведен тривиальный пример:
public class MessageHandler1 : DelegatingHandler < protected async override TaskSendAsync( HttpRequestMessage request, CancellationToken cancellationToken) < Debug.WriteLine("Process request"); // Call the inner handler. var response = await base.SendAsync(request, cancellationToken); Debug.WriteLine("Process response"); return response; >>
Вызов к base.SendAsync выполняется асинхронно. Если обработчик выполняет какие-либо действия после этого вызова, используйте ключевое слово await, как показано ниже.
Делегированный обработчик также может пропустить внутренний обработчик и напрямую создать ответ:
public class MessageHandler2 : DelegatingHandler < protected override TaskSendAsync( HttpRequestMessage request, CancellationToken cancellationToken) < // Create the response. var response = new HttpResponseMessage(HttpStatusCode.OK) < Content = new StringContent("Hello!") >; // Note: TaskCompletionSource creates a task that does not contain a delegate. var tsc = new TaskCompletionSource(); tsc.SetResult(response); // Also sets the task state to "RanToCompletion" return tsc.Task; > >
Если делегирующие обработчики создают ответ без вызова base.SendAsync , запрос пропускает остальную часть конвейера. Это может быть полезно для обработчика, который проверяет запрос (создает ответ об ошибке).

Добавление обработчика в конвейер
Чтобы добавить обработчик сообщений на стороне сервера, добавьте обработчик в коллекцию HttpConfiguration.MessageHandlers . Если вы использовали шаблон «веб-приложение ASP.NET MVC 4» для создания проекта, это можно сделать в классе WebApiConfig :
public static class WebApiConfig < public static void Register(HttpConfiguration config) < config.MessageHandlers.Add(new MessageHandler1()); config.MessageHandlers.Add(new MessageHandler2()); // Other code not shown. >>
Обработчики сообщений вызываются в том же порядке, что и в коллекции MessageHandlers . Так как они являются вложенными, ответное сообщение перемещается в другом направлении. То есть последний обработчик является первым, кто получает ответные сообщения.
Обратите внимание, что вам не нужно задавать внутренние обработчики. платформа веб-API автоматически подключает обработчики сообщений.
Если вы используете самостоятельное размещение, создайте экземпляр класса HttpSelfHostConfiguration и добавьте обработчики в коллекцию MessageHandlers .
var config = new HttpSelfHostConfiguration("http://localhost"); config.MessageHandlers.Add(new MessageHandler1()); config.MessageHandlers.Add(new MessageHandler2());
Теперь рассмотрим некоторые примеры пользовательских обработчиков сообщений.
Пример: X-HTTP-Method-Override
X-HTTP-Method-Override — это нестандартный заголовок HTTP. Он предназначен для клиентов, которые не могут отправлять определенные типы HTTP-запросов, например PUT или DELETE. Вместо этого клиент отправляет запрос POST и задает для заголовка X-HTTP-Method-Override нужный метод. Пример:
X-HTTP-Method-Override: PUT
Ниже приведен обработчик сообщений, который добавляет поддержку X-HTTP-Method-Override:
public class MethodOverrideHandler : DelegatingHandler < readonly string[] _methods = < "DELETE", "HEAD", "PUT" >; const string _header = "X-HTTP-Method-Override"; protected override Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) < // Check for HTTP POST with the X-HTTP-Method-Override header. if (request.Method == HttpMethod.Post && request.Headers.Contains(_header)) < // Check if the header value is in our methods list. var method = request.Headers.GetValues(_header).FirstOrDefault(); if (_methods.Contains(method, StringComparer.InvariantCultureIgnoreCase)) < // Change the request method. request.Method = new HttpMethod(method); >> return base.SendAsync(request, cancellationToken); > >
В методе SendAsync обработчик проверяет, является ли сообщение запроса запросом POST и содержит ли оно заголовок X-HTTP-Method-Override. Если это так, он проверяет значение заголовка, а затем изменяет метод запроса. Наконец, обработчик вызывает base.SendAsync для передачи сообщения следующему обработчику.
Когда запрос достигает класса HttpControllerDispatcher , HttpControllerDispatcher перенаправит запрос на основе обновленного метода запроса.
Пример. Добавление пользовательского заголовка ответа
Ниже приведен обработчик сообщений, который добавляет настраиваемый заголовок в каждое ответное сообщение:
// .Net 4.5 public class CustomHeaderHandler : DelegatingHandler < async protected override TaskSendAsync( HttpRequestMessage request, CancellationToken cancellationToken) < HttpResponseMessage response = await base.SendAsync(request, cancellationToken); response.Headers.Add("X-Custom-Header", "This is my custom header."); return response; >>
Сначала обработчик вызывает base.SendAsync для передачи запроса внутреннему обработчику сообщений. Внутренний обработчик возвращает ответное сообщение, но делает это асинхронно с помощью объекта Task . Ответное сообщение недоступно, пока base.SendAsync не завершится асинхронно.
В этом примере используется ключевое слово await для асинхронного выполнения работы после SendAsync завершения. Если вы используете платформа .NET Framework 4.0, используйте задачу. Метод ContinueWith:
public class CustomHeaderHandler : DelegatingHandler < protected override TaskSendAsync( HttpRequestMessage request, CancellationToken cancellationToken) < return base.SendAsync(request, cancellationToken).ContinueWith( (task) => < HttpResponseMessage response = task.Result; response.Headers.Add("X-Custom-Header", "This is my custom header."); return response; >); > >
Пример. Проверка ключа API
Некоторые веб-службы требуют, чтобы клиенты включали ключ API в свой запрос. В следующем примере показано, как обработчик сообщений может проверка запросы на допустимый ключ API:
public class ApiKeyHandler : DelegatingHandler < public string Key < get; set; >public ApiKeyHandler(string key) < this.Key = key; >protected override Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) < if (!ValidateKey(request)) < var response = new HttpResponseMessage(HttpStatusCode.Forbidden); var tsc = new TaskCompletionSource(); tsc.SetResult(response); return tsc.Task; > return base.SendAsync(request, cancellationToken); > private bool ValidateKey(HttpRequestMessage message) < var query = message.RequestUri.ParseQueryString(); string key = query["key"]; return (key == Key); >>
Этот обработчик ищет ключ API в строке запроса URI. (В этом примере предполагается, что ключ является статической строкой. Реальная реализация, вероятно, будет использовать более сложную проверку.) Если строка запроса содержит ключ, обработчик передает запрос внутреннему обработчику.
Если у запроса нет допустимого ключа, обработчик создает ответное сообщение с состоянием 403 — Запрещено. В этом случае обработчик не вызывает base.SendAsync , поэтому внутренний обработчик никогда не получает запрос, как и контроллер. Таким образом, контроллер может предположить, что все входящие запросы имеют действительный ключ API.
Если ключ API применяется только к определенным действиям контроллера, рекомендуется использовать фильтр действий вместо обработчика сообщений. Фильтры действий выполняются после выполнения маршрутизации URI.
Обработчики сообщений Per-Route
Обработчики в коллекции HttpConfiguration.MessageHandlers применяются глобально.
Кроме того, можно добавить обработчик сообщений к определенному маршруту при определении маршрута:
public static class WebApiConfig < public static void Register(HttpConfiguration config) < config.Routes.MapHttpRoute( name: "Route1", routeTemplate: "api//", defaults: new < >); config.Routes.MapHttpRoute( name: "Route2", routeTemplate: "api2//", defaults: new < >, constraints: null, handler: new MessageHandler2() // per-route message handler ); config.MessageHandlers.Add(new MessageHandler1()); // global message handler > >
В этом примере, если универсальный код ресурса (URI) запроса совпадает с «Route2», запрос отправляется в MessageHandler2 . На следующей схеме показан конвейер для этих двух маршрутов:

Обратите внимание, что MessageHandler2 заменяет httpControllerDispatcher по умолчанию. В этом примере MessageHandler2 создается ответ, а запросы, соответствующие Route2, никогда не отправляются к контроллеру. Это позволяет заменить весь механизм контроллера веб-API собственной пользовательской конечной точкой.
Кроме того, обработчик сообщений для каждого маршрута может делегировать httpControllerDispatcher, который затем отправляется контроллеру.

В следующем коде показано, как настроить этот маршрут:
// List of delegating handlers. DelegatingHandler[] handlers = new DelegatingHandler[] < new MessageHandler3() >; // Create a message handler chain with an end-point. var routeHandlers = HttpClientFactory.CreatePipeline( new HttpControllerDispatcher(config), handlers); config.Routes.MapHttpRoute( name: "Route2", routeTemplate: "api2//", defaults: new < >, constraints: null, handler: routeHandlers );
Обратная связь
Были ли сведения на этой странице полезными?
Server handler что это
Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Последнее обновление: 31.10.2015
HTTP-обработчики (HTTP Handlers) используются для генерации содержимого ответа на HTTP-запрос. Мы можем использовать HTTP-обработчики для настройки обработчик запросов. При обработке одного запроса мы можем задействовать несколько различных модулей, но только один http-обработчик может быть сопоставлен с запросом.
HTTP-обработчик представляет класс, реализующий интерфейс System.Web.IHttpHandler . Данный интерфейс определяет один метод и одно свойство:
- ProcessRequest(context) : данный метод в качестве параметра принимает объект контекста запроса HttpContext и генерирует ответ клиенту
- IsReusable : это свойство указывает, будет ли данный обработчик использоваться другими запросами
HTTP-обработчик выбирается системой после возникновения события MapRequestHandler . И сразу после выбора обработчика срабатывает событие PostMapRequestHandler
Непосредственная генерация ответа обработчиком происходит после события PreRequestHandlerExecute — после этого события происходит вызов метода ProcessRequest и генерация ответа. А сразу после генерации ответа возникает событие PostRequestHandlerExecute
Рассмотрим на примере. Создадим свой простенький Http-обработчик.
Для этого вначале определим в проекте каталог Handlers, который будет содержать файлы обработчиков. Затем в этот каталог добавим новый класс UserInfoHandler:
public class UserInfoHandler : IHttpHandler < public void ProcessRequest(HttpContext context) < string result = "Ваш IP: "+context.Request.UserHostAddress+"
"; result+="UserAgent: "+context.Request.UserAgent+"
"; context.Response.Write(result); > public bool IsReusable < get < return false; >> >
Обработчик просто возвращает ip и данные строки user-agent клиенту.
Теперь этот обработчик надо подключить к обработке запросов. Это можно сделать двумя способами. Первый способ заключается в вызове обработчика через обработчик маршрутов. Для этого откроем файл RouteConfig и изменим его содержание следующим образом:
using LifeCycleApp.Handlers; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace LifeCycleApp < public class RouteConfig < public static void RegisterRoutes(RouteCollection routes) < routes.IgnoreRoute(".axd/"); routes.Add(new Route("handler/", new CustomRouteHandler())); routes.MapRoute( name: "Default", url: "//", defaults: new < controller = "Home", action = "Index", >); > > // обработчик маршрута class CustomRouteHandler : IRouteHandler < public IHttpHandler GetHttpHandler(RequestContext requestContext) < return new UserInfoHandler(); >> >
Выражение routes.Add(new Route(«handler/», new CustomRouteHandler())) добавляет новый маршрут, который обрабатывает класс CustomRouteHandler. В свою очередь этот обработчик маршрутов будет вызывать определенный выше HTTP-обработчик.
Второй способ заключается в определении обработчика в файле web.config. Для этого в файле конфигурации в узле system.webServer (если его нет, то надо создать) пропишем определение обработчика:
Все обработчики задаются в элементе handlers . Каждое определение имеет следующие атрибуты:
- name : уникальное название обработчика
- path : запрос URL, который будет обрабатываться обработчиком
- verb : тип запрос, например, GET. Мы также можем поставить любой тип запроса — в этом случае используется звездочка (*)
- type : полный тип класса обработчика
Кроме регистрации в web.config нам надо также добавить игнорирование маршрута в файле RouteConfig.cs, иначе система маршрутизации будет неправильно обрабатывать данный маршрут:
public class RouteConfig < public static void RegisterRoutes(RouteCollection routes) < routes.IgnoreRoute(".axd/"); routes.IgnoreRoute("handler/"); routes.MapRoute( name: "Default", url: "//", defaults: new < controller = "Home", action = "Index", >); > >
Функция Handler
Функция Handler — это определяемая программой функция повторного вызова, используемая функцией RegisterServiceCtrlHandler. Сервисная программа использует ее как функцию управления обработчиком конкретного сервиса. Тип LPHANDLER_FUNCTION определяет указатель на эту функцию. Handler — это имя — заместитель для определяемого программой имени.
Эта функция была заменена управляющей обработчиком функцией HandlerEx, используемой функцией RegisterServiceCtrlHandlerEx. Сервис может использовать любое управление обработчиком, но новое управление поддерживает определяемые пользователем данные контекста и дополнительные управляющие коды.
VOID WINAPI Handler( DWORD fdwControl );
fdwControl [in] Управляющий код. Этот параметр может быть одним из следующих значений.
| Управляющий код | Предназначение |
|---|---|
| SERVICE_CONTROL_CONTINUE | Уведомляет, что временно остановленный сервис должен возобновить работу. |
| SERVICE_CONTROL_INTERROGATE | Уведомляет сервис, что он должен сообщить о информацию о его текущем состоянии диспетчеру управления сервисами (SCM). |
| SERVICE_CONTROL_NETBINDADD | Уведомляет сетевой сервис, что есть новый компонент для соединения. Сервис должен соединиться с новым компонентом. Однако, этот управляющий код не рекомендуется применять; вместо него используйте функциональные возможности технологии Plug and Play. |
Дополнительную информацию, см. в разделе Замечания.
Этим параметром также может быть определяемый пользователем управляющий код, как описано в таблице ниже.
| Управляющий код | Предназначение |
|---|---|
| Диапазон от 128 до 255. | Служба определяет действие, связанное с кодом органа управления. |
Возвращаемые значения
Эта функция не возвращает значение.
Замечания
Когда служба стартует, ее функция ServiceMain должна немедленно вызвать функцию RegisterServiceCtrlHandler, чтобы определить функцию Handler , которая обрабатывает запросы на управление.
Диспетчер управления в пределах главного потока процесса службы вызывает функцию обработки управления для указанной службы всякий раз, когда он получает запрос на управление от диспетчера управления службами. После обработки запроса на управление, обрабатывающая программа управления должна вызвать функцию SetServiceStatus, чтобы сообщить о ее текущем состоянии диспетчеру управления службами.
Когда диспетчер управления службами отправляет управляющий код службе, он ждет обработчика функции, чтобы возвратить значение перед отправкой дополнительных управляющих кодов другим службам. Если обработчик функции не возвращает значение быстро, диспетчер может заблокировать другие службы, чтобы они не получили управляющих кодов.
Управляющий код SERVICE_CONTROL_SHUTDOWN должен быть обработан только службами, которые должны безусловно очищаться в ходе закрытия, потому что имеется только ограниченное время (около 20 секунд) доступное для закрытия службы. После того, как это время истекает, система возобновляет процесс закрытия независимо от того, завершается ли закрытие службы полностью.
| Обратите внимание! на то, что это, если систему оставляют в состоянии закрытия (не перезапускают или не выключают питание), служба, продолжает запускаться. |
Если служба нуждается в большем количестве времени, чтобы очистить память, она должна отправить сообщения о состоянии STOP_PENDING , наряду с указанием ожидать, таким образом диспетчер службы знает, как долго ждать перед оповещением в системе, что закрытие службы завершается полностью. Однако, чтобы воспрепятствовать службе остановить закрытие, есть предел тому, как долго диспетчер службы должен ждать. Чтобы изменять этот срок, модифицируйте значение WaitToKillServiceTimeout в следующем ключе реестра:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
Использование обработчиков в Apache
Этот документ описывает использование обработчиков (handlers) в Apache.
- Что такое обработчик
- Примеры
- Замечание для программистов
Что такое обработчик
Обработчик является внутренней структурой Apache, которая задаёт поведение сервера при обработке запрашиваемого файла. Как правило, каждому файлу соответствует свой внутренний обработчик, который назначается сервером исходя из типа файла. Обычно файлы просто возвращаются пользователю, но некоторые типы файлов предварительно обрабатываются (handled) сервером.
В Apache 1.1 добавлена возможность использовать обработчики явно. Причём обработка файлов может основываться теперь не только на их типе, но и на расширении файлов или их местонахождении. Это представляется наиболее удачным решением, во-первых потому, что это решение элегантно, а во-вторых, это позволяет ассоциировать с файлом как тип, так и обработчик. (См. также «Файлы с несколькими расширениями»)
Обработчики могут представлять из себя как вкомпилированные в сервер (или подключаемые с помощью модулей) функции, или они могут быть добавлены с помощью директивы Action . В стандартном дистрибутиве сервера имеются следующие встроенные обработчики:
- default-handler: Посылает файл, используя функцию default_handler() , которая является обработчиком по-умолчанию для статических файлов. (ядро)
- send-as-is: Посылает файл, содержащий в себе HTTP заголовки, как есть. ( mod_asis )
- cgi-script: Обрабатывает файл как CGI-скрипт. ( mod_cgi )
- imap-file: Обрабатывает файл как карту изображения (imagemap). ( mod_imap )
- server-info: Возвращает конфигурационную информацию сервера. ( mod_info )
- server-status: Возвращает отчет о состоянии сервера. ( mod_status )
- type-map: Обрабатывает файл как карту типов (type map). ( mod_negotiation )
Примеры
Обработка статического документа CGI-скриптом
При использовании следующих директив, каждый запрос файла с расширением html будет запускать на выполнение CGI-скрипт footer.pl для предварительной обработки запрашиваемого файла.
Action add-footer /cgi-bin/footer.pl
AddHandler add-footer .html
В этом случает CGI-скрипт ответственен за то, чтобы выслать пользователю запрошенный документ (на который указывает переменная окружения PATH_TRANSLATED ), сделав в нём предварительно все необходимые изменения.
Файлы с HTTP заголовками
Следующие несколько директив заставят выполняться обработчик send-as-is , который используется для файлов, содержащих свои собственные HTTP-заголовки. Все файлы в каталоге /web/htdocs/asis/ будут обрабатываться обработчиком send-as-is , независимо от их расширения.
Замечание для программистов
Для того чтобы можно было использовать обработчики, в Apache API были внесены некоторые дополнения. В частности, в структуру request_rec было добавлено новое поле:
Если вы хотите в своём модуле использовать обработчик, то всё, что вам надо сделать, это записать в r->handler имя соответствующего обработчика, причём сделать это необходимо перед тем, как запрос доходит до стадии invoke_handler . Обработчики реализуются точно так же, как и раньше, за исключением лишь того, что теперь необходимо указывать имя обработчика, а не тип содержимого (content type). Хотя это и не является обязательным, но существуют следующие правила именования обработчиков — необходимо использовать слова, разделённые дефисом и не содержащие косых черт — это позволит не пересекаться с пространством имён медиа-типов (media type).
| Copyright Apache.ru © 1999-2017, All Rights Reserved | Разработка сайта: Inside.ru |
| РЕКЛАМА НА САЙТЕ: 6.4.2 —> | | |