ASP.NET Web API 中的 HttpClient 消息处理程序

消息处理程序是接收 HTTP 请求并返回 HTTP 响应的类。

通常,一系列消息处理程序链接在一起。 第一个处理程序接收 HTTP 请求,执行一些处理,并将请求提供给下一个处理程序。 在某个时候,会创建响应并返回链。 此模式称为 委派 处理程序。

链接在一起的消息处理程序示意图,说明了接收 H T T P 请求并返回 H T P 响应的过程。

在客户端, HttpClient 类使用消息处理程序来处理请求。 默认处理程序为 HttpClientHandler,它通过网络发送请求并从服务器获取响应。 可以将自定义消息处理程序插入客户端管道:

将自定义消息处理程序插入客户端管道的过程示意图。显示使用消息处理程序处理请求的 h t t p Client 类。

注意

ASP.NET Web API还在服务器端使用消息处理程序。 有关详细信息,请参阅 HTTP 消息处理程序

自定义消息处理程序

若要编写自定义消息处理程序,请从 System.Net.Http.DelegatingHandler 派生并重写 SendAsync 方法。 下面是方法签名:

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

方法采用 HttpRequestMessage 作为输入,并异步返回 HttpResponseMessage。 典型的实现将执行以下操作:

  1. 处理请求消息。
  2. 调用 base.SendAsync 以将请求发送到内部处理程序。
  3. 内部处理程序返回响应消息。 (此步骤是异步的。)
  4. 处理响应并将其返回到调用方。

以下示例演示一个消息处理程序,该处理程序将自定义标头添加到传出请求:

class MessageHandler1 : DelegatingHandler
{
    private int _count = 0;

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        System.Threading.Interlocked.Increment(ref _count);
        request.Headers.Add("X-Custom-Header", _count.ToString());
        return base.SendAsync(request, cancellationToken);
    }
}

base.SendAsync 的调用是异步的。 如果处理程序在此调用后执行了任何工作,请使用 await 关键字 (keyword) 在方法完成后继续执行。 以下示例演示记录错误代码的处理程序。 日志记录本身不是很有趣,但该示例演示了如何在处理程序内获取响应。

class LoggingHandler : DelegatingHandler
{
    StreamWriter _writer;

    public LoggingHandler(Stream stream)
    {
        _writer = new StreamWriter(stream);
    }

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);

        if (!response.IsSuccessStatusCode)
        {
            _writer.WriteLine("{0}\t{1}\t{2}", request.RequestUri, 
                (int)response.StatusCode, response.Headers.Date);
        }
        return response;
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _writer.Dispose();
        }
        base.Dispose(disposing);
    }
}

将消息处理程序添加到客户端管道

若要将自定义处理程序添加到 HttpClient,请使用 HttpClientFactory.Create 方法:

HttpClient client = HttpClientFactory.Create(new Handler1(), new Handler2(), new Handler3());

消息处理程序按将消息处理程序传递到 Create 方法的顺序调用。 由于处理程序是嵌套的,因此响应消息会向另一个方向传播。 也就是说,最后一个处理程序是第一个获取响应消息的处理程序。