【ASP.NET Web API教程】5.1 HTTP消息处理器

简介: 原文:【ASP.NET Web API教程】5.1 HTTP消息处理器注:本文是【ASP.NET Web API系列教程】的一部分,如果您是第一次看本系列教程,请先看前面的内容。 5.1 HTTP Message Handlers 5.
原文: 【ASP.NET Web API教程】5.1 HTTP消息处理器

注:本文是【ASP.NET Web API系列教程】的一部分,如果您是第一次看本系列教程,请先看前面的内容。

5.1 HTTP Message Handlers
5.1 HTTP消息处理器

本文引自:http://www.asp.net/web-api/overview/working-with-http/http-message-handlers

By Mike Wasson | February 13, 2012
作者:Mike Wasson |日期:2012-2-13

A message handler is a class that receives an HTTP request and returns an HTTP response. Message handlers derive from the abstract HttpMessageHandler class.
消息处理器是一个接收HTTP请求并返回HTTP响应的类。消息处理器派生于HttpMessageHandler类。

Typically, a series of message handlers are chained together. The first handler receives an HTTP request, does some processing, and gives the request to the next handler. At some point, the response is created and goes back up the chain. This pattern is called a delegating handler.
典型地,一系列消息处理器被链接在一起。第一个处理器接收HTTP请求、进行一些处理,并将该请求交给下一个处理器。在某个点上,创建响应并沿链返回。这种模式称为委托处理器(delegating handler)(如图5-1所示)。

WebAPI5-1

图中:Request:请求,Delegating Handler:委托处理器,Inner Handler:内部处理器,Response:响应

图5-1. 消息处理器链

Server-Side Message Handlers
服务器端消息处理器

On the server side, the Web API pipeline uses some built-in message handlers:
在服务器端,Web API管线使用一些内建的消息处理器:

  • HttpServer gets the request from the host.
    HttpServer获取从主机发来的请求。
  • HttpRoutingDispatcher dispatches the request based on the route.
    HttpRoutingDispatcher(HTTP路由分发器)基于路由对请求进行分发。
  • HttpControllerDispatcher sends the request to a Web API controller.
    HttpControllerDispatcher(HTTP控制器分发器)将请求发送给一个Web API控制器。

You can add custom handlers to the pipeline. Message handlers are good for cross-cutting concerns that operate at the level of HTTP messages (rather than controller actions). For example, a message handler might:
可以把自定义处理器添加到该管线上。对于在HTTP消息层面上(而不是在控制器动作上)进行操作的交叉关注,消息处理器是很有用的。例如,消息处理器可以:

  • Read or modify request headers.
    读取或修改请求报头。
  • Add a response header to responses.
    对响应添加响应报头。
  • Validate requests before they reach the controller.
    在请求到达控制器之前验证请求。

This diagram shows two custom handlers inserted into the pipeline:
下图显示了插入到管线的两个自定义处理器(见图5-2):

WebAPI5-2

图5-2. 服务器端消息处理器

On the client side, HttpClient also uses message handlers. For more information, see HttpClient Message Handlers.
在客户端,HttpClient也使用消息处理器。更多信息参阅“Http消息处理器”(本系列教程的第3.4小节 — 译者注)。

Custom Message Handlers
自定义消息处理器

To write a custom message handler, derive from System.Net.Http.DelegatingHandler and override the SendAsync method. This method has the following signature:
要编写一个自定义消息处理器,需要通过System.Net.Http.DelegatingHandler进行派生,并重写SendAsync方法。该方法有以下签名:

Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage request, CancellationToken cancellationToken);

The method takes an HttpRequestMessage as input and asynchronously returns an HttpResponseMessage. A typical implementation does the following:
该方法以HttpRequestMessage作为输入参数,并异步地返回一个HttpResponseMessage。典型的实现要做以下事:

  1. Process the request message.
    处理请求消息。
  2. Call base.SendAsync to send the request to the inner handler.
    调用base.SendAsync将该请求发送给内部处理器。
  3. The inner handler returns a response message. (This step is asynchronous.)
    内部处理器返回响应消息。(此步是异步的。)
  4. Process the response and return it to the caller.
    处理响应,并将其返回给调用者。

Here is a trivial example:
以下是一个价值不高的示例:

public class MessageHandler1 : DelegatingHandler 
{ 
    protected async override Task<HttpResponseMessage> SendAsync( 
        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; 
    } 
}

The call to base.SendAsync is asynchronous. If the handler does any work after this call, use the await keyword, as shown.
base.SendAsync的调用是异步的。如果处理器在调用之后有工作要做,需使用await关键字,如上所示。

A delegating handler can also skip the inner handler and directly create the response:
委托处理器也可以跳过内部处理器,并直接创建响应:

public class MessageHandler2 : DelegatingHandler 
{ 
    protected override Task<HttpResponseMessage> SendAsync( 
        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. // 注:TaskCompletionSource创建一个不含委托的任务。 var tsc = new TaskCompletionSource<HttpResponseMessage>(); tsc.SetResult(response); // Also sets the task state to "RanToCompletion" // 也将此任务设置成“RanToCompletion(已完成)” return tsc.Task; } }

If a delegating handler creates the response without calling base.SendAsync, the request skips the rest of the pipeline. This can be useful for a handler that validates the request (creating an error response).
如果委托处理器未调用base.SendAsync创建了响应,该请求会跳过管线的其余部分(如图5-3所示)。这对验证请求(创建错误消息)的处理器,可能是有用的。

WebAPI5-3

图5-3. 被跳过的处理器

Adding a Handler to the Pipeline
向管线添加一个处理器

To add a message handler on the server side, add the handler to the HttpConfiguration.MessageHandlers collection. If you used the "ASP.NET MVC 4 Web Application" template to create the project, you can do this inside the WebApiConfig class:
要在服务器端添加消息处理器,需要将该处理器添加到HttpConfiguration.MessageHandlers集合。如果创建项目用的是“ASP.NET MVC 4 Web应用程序”模板,你可以在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(未列出其它代码)... } }

Message handlers are called in the same order that they appear in MessageHandlers collection. Because they are nested, the response message travels in the other direction. That is, the last handler is the first to get the response message.
消息处理器是按它们在MessageHandlers集合中出现的顺序来调用的。因为它们是内嵌的,响应消息以反方向运行,即,最后一个处理器最先得到响应消息。

Notice that you don't need to set the inner handlers; the Web API framework automatically connects the message handlers.
注意,不需要设置内部处理器;Web API框架会自动地连接这些消息处理器。

If you are self-hosting, create an instance of the HttpSelfHostConfiguration class and add the handlers to the MessageHandlers collection.
如果是“自托管”(本系列教程的第8.1小节 — 译者注)的,需要创建一个HttpSelfHostConfiguration类的实例,并将处事器添加到MessageHandlers集合。

var config = new HttpSelfHostConfiguration("http://localhost"); 
config.MessageHandlers.Add(new MessageHandler1()); 
config.MessageHandlers.Add(new MessageHandler2());

Now let's look at some examples of custom message handlers.
现在,让我们看一些自定义消息处理器的例子。

Example: X-HTTP-Method-Override
示例:X-HTTP-Method-Override

X-HTTP-Method-Override is a non-standard HTTP header. It is designed for clients that cannot send certain HTTP request types, such as PUT or DELETE. Instead, the client sends a POST request and sets the X-HTTP-Method-Override header to the desired method. For example:
X-HTTP-Method-Override是一个非标准的HTTP报头。这是为不能发送某些HTTP请求类型(如PUT或DELETE)的客户端而设计的。因此,客户端可以发送一个POST请求,并把X-HTTP-Method-Override设置为所希望的方法(意即,对于不能发送PUT或DELETE请求的客户端,可以让它发送POST请求,然后用X-HTTP-Method-Override把这个POST请求重写成PUT或DELETE请求 — 译者注)。例如:

X-HTTP-Method-Override: PUT

Here is a message handler that adds support for X-HTTP-Method-Override:
以下是添加了X-HTTP-Method-Override支持的一个消息处事器:

public class MethodOverrideHandler : DelegatingHandler       
{ 
    readonly string[] _methods = { "DELETE", "HEAD", "PUT" }; 
    const string _header = "X-HTTP-Method-Override"; 
protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { // Check for HTTP POST with the X-HTTP-Method-Override header. // 检查带有X-HTTP-Method-Override报头的HTTP POST。 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); } }

In the SendAsync method, the handler checks whether the request message is a POST request, and whether it contains the X-HTTP-Method-Override header. If so, it validates the header value, and then modifies the request method. Finally, the handler calls base.SendAsync to pass the message to the next handler.
SendAsync方法中,处理器检查了该请求消息是否是一个POST请求,以及它是否含有X-HTTP-Method-Override报头。如果是,它会验证报头值,然后修改请求方法。最后,处理器调用base.SendAsync,把消息传递给下一下处事器。

When the request reaches the HttpControllerDispatcher class, HttpControllerDispatcher will route the request based on the updated request method.
当请求到达HttpControllerDispatcher类时,HttpControllerDispatcher会根据这个已被更新的请求方法对该请求进行路由。

Example: Adding a Custom Response Header
示例:添加自定义响应报头

Here is a message handler that adds a custom header to every response message:
以下是一个把自定义报头添加到每个响应消息的消息处理器:

// .Net 4.5 
public class CustomHeaderHandler : DelegatingHandler 
{ 
    async protected override Task<HttpResponseMessage> SendAsync( 
            HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
        HttpResponseMessage response = await base.SendAsync(request, cancellationToken); 
        response.Headers.Add("X-Custom-Header", "This is my custom header."); 
        return response; 
    } 
}

First, the handler calls base.SendAsync to pass the request to the inner message handler. The inner handler returns a response message, but it does so asynchronously using a Task<T> object. The response message is not available until base.SendAsync completes asynchronously.
首先,该处理器调用base.SendAsync把请求传递给内部消息处理器。内部处理器返回一条响应消息,但它是用Task<T>对象异步地做这件事的。在base.SendAsync异步完成之前,响应消息是不可用的。

This example uses the await keyword to perform work asynchronously after SendAsync completes. If you are targeting .NET Framework 4.0, use the Task.ContinueWith method:
这个示例使用了await关键字,以便在SendAsync完成之后异步地执行任务。如果你的目标框架是.NET Framework 4.0,需使用Task.ContinueWith方法:

public class CustomHeaderHandler : DelegatingHandler 
{ 
    protected override Task<HttpResponseMessage> SendAsync( 
        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; 
            } 
        ); 
    } 
}

Example: Checking for an API Key
示例:检查API键

Some web services require clients to include an API key in their request. The following example shows how a message handler can check requests for a valid API key:
有些Web服务需要客户端在其请求中包含一个API键。以下示例演示一个消息处理器如何针对一个有效的API键来检查请求:

public class ApiKeyHandler : DelegatingHandler 
{ 
    public string Key { get; set; } 
public ApiKeyHandler(string key) { this.Key = key; }
protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { if (!ValidateKey(request)) { var response = new HttpResponseMessage(HttpStatusCode.Forbidden); var tsc = new TaskCompletionSource<HttpResponseMessage>(); 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); } }

This handler looks for the API key in the URI query string. (For this example, we assume that the key is a static string. A real implementation would probably use more complex validation.) If the query string contains the key, the handler passes the request to the inner handler.
该处理器在URI查询字符串中查找API键(对此例而言,我们假设键是一个静态字符串。一个真实的实现可能会使用更复杂的验证。)如果查询字符串包含这个键,该处理便把请求传递给内部处理器。

If the request does not have a valid key, the handler creates a response message with status 403, Forbidden. In this case, the handler does not call base.SendAsync, so the inner handler never receives the request, nor does the controller. Therefore, the controller can assume that all incoming requests have a valid API key.
如果请求没有一个有效的键,该处理器便创建一个状态为“403 — 拒绝访问”的响应消息。在这种情况下,该处理器不会调用base.SendAsync,于是,内部处理不会收到这个请求,控制器也就不会收到这个请求了。因此,控制器可以假设所有输入请求都有一个有效的API键。

If the API key applies only to certain controller actions, consider using an action filter instead of a message handler. Action filters run after URI routing is performed.
如果API键仅运用于某些控制器动作,请考虑使用动作过滤器,而不是消息处理器。动作过滤在URI路由完成之后运行。

Per-Route Message Handlers
单路由消息处理器

Handlers in the HttpConfiguration.MessageHandlers collection apply globally.
HttpConfiguration.MessageHandlers集合中的处理器是全局运用的。

Alternatively, you can add a message handler to a specific route when you define the route:
另一种办法是,在定义路由时,对一个特定的路由添加消息处理器:

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
        config.Routes.MapHttpRoute( 
            name: "Route1", 
            routeTemplate: "api/{controller}/{id}", 
            defaults: new { id = RouteParameter.Optional } 
        ); 
config.Routes.MapHttpRoute( name: "Route2", routeTemplate: "api2/{controller}/{id}", defaults: new { id = RouteParameter.Optional }, constraints: null, handler: new MessageHandler2() // per-route message handler(单路由消息处理器) );
config.MessageHandlers.Add(new MessageHandler1()); // global message handler(全局消息处理器) } }

In this example, if the request URI matches "Route2", the request is dispatched to MessageHandler2. The following diagram shows the pipeline for these two routes:
在这个例子中,如果请求的URI与“Route2”匹配,该请求被分发给MessageHandler2。图5-4展示了这两个路由的管线:

WebAPI5-4

图5-4. 单路由消息处理器

Notice that MessageHandler2 replaces the default HttpControllerDispatcher. In this example, MessageHandler2 creates the response, and requests that match "Route2" never go to a controller. This lets you replace the entire Web API controller mechanism with your own custom endpoint.
注意,MessageHandler2替换了默认的HttpControllerDispatcher。在这个例子中,MessageHandler2创建响应,而与“Route2”匹配的请求不会到达控制器。这让你可以用自己的自定义端点来替换整个Web API控制器机制。

Alternatively, a per-route message handler can delegate to HttpControllerDispatcher, which then dispatches to a controller.
另一种办法是,单路由消息处理器可以委托给HttpControllerDispatcher,然后由它来分发给控制器(如图5-5所示)。

WebAPI5-5

图5-5. 将消息处理器委托给HttpControllerDispatcher

The following code shows how to configure this route:
以下代码演示如何配置这种路由:

// 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/{controller}/{id}", 
    defaults: new { id = RouteParameter.Optional }, 
    constraints: null, 
    handler: routeHandlers
); 

看完此文如果觉得有所收获,请给个推荐

目录
相关文章
|
11天前
|
开发框架 前端开发 JavaScript
ASP.NET Web Pages - 教程
ASP.NET Web Pages 是一种用于创建动态网页的开发模式,采用HTML、CSS、JavaScript 和服务器脚本。本教程聚焦于Web Pages,介绍如何使用Razor语法结合服务器端代码与前端技术,以及利用WebMatrix工具进行开发。适合初学者入门ASP.NET。
|
2月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
53 4
|
2月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
147 3
|
2月前
|
网络安全 开发工具 数据安全/隐私保护
|
1月前
|
前端开发 API 开发者
Python Web开发者必看!AJAX、Fetch API实战技巧,让前后端交互如丝般顺滑!
在Web开发中,前后端的高效交互是提升用户体验的关键。本文通过一个基于Flask框架的博客系统实战案例,详细介绍了如何使用AJAX和Fetch API实现不刷新页面查看评论的功能。从后端路由设置到前端请求处理,全面展示了这两种技术的应用技巧,帮助Python Web开发者提升项目质量和开发效率。
44 1
|
1月前
|
XML 安全 PHP
PHP与SOAP Web服务开发:基础与进阶教程
本文介绍了PHP与SOAP Web服务的基础和进阶知识,涵盖SOAP的基本概念、PHP中的SoapServer和SoapClient类的使用方法,以及服务端和客户端的开发示例。此外,还探讨了安全性、性能优化等高级主题,帮助开发者掌握更高效的Web服务开发技巧。
|
1月前
|
JSON API 数据格式
如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架
本文介绍了如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架,适合小型项目和微服务。文章从环境准备、创建基本Flask应用、定义资源和路由、请求和响应处理、错误处理等方面进行了详细说明,并提供了示例代码。通过这些步骤,读者可以快速上手构建自己的RESTful API。
38 2
|
2月前
|
监控 负载均衡 API
Web、RESTful API 在微服务中有哪些作用?
在微服务架构中,Web 和 RESTful API 扮演着至关重要的角色。它们帮助实现服务之间的通信、数据交换和系统的可扩展性。
51 2
|
2月前
|
人工智能 搜索推荐 API
用于企业AI搜索的Bocha Web Search API,给LLM提供联网搜索能力和长文本上下文
博查Web Search API是由博查提供的企业级互联网网页搜索API接口,允许开发者通过编程访问博查搜索引擎的搜索结果和相关信息,实现在应用程序或网站中集成搜索功能。该API支持近亿级网页内容搜索,适用于各类AI应用、RAG应用和AI Agent智能体的开发,解决数据安全、价格高昂和内容合规等问题。通过注册博查开发者账户、获取API KEY并调用API,开发者可以轻松集成搜索功能。
|
2月前
|
开发框架 NoSQL MongoDB
C#/.NET/.NET Core开发实战教程集合
C#/.NET/.NET Core开发实战教程集合