• HttpClientFactory in ASP.NET Core 2.1 Part 3: 对处理器使用对外请求中间件


    HttpClientFactory in ASP.NET Core 2.1 Part 3: 对处理器使用对外请求中间件

    原文地址:https://www.stevejgordon.co.uk/httpclientfactory-aspnetcore-outgoing-request-middleware-pipeline-delegatinghandlers

    DelegatingHandlers

    为了有一个更为清晰的开始,该特性的许多方面已经存在很长时间了,HttpClientFactory 简化了消费这些构建块,使它更加易用,通过更为可组合和清晰的 API。

    当发出 Http 请求的时候,通常会需要跨越多个边界,你可能希望通过给定的 HttpClient 应用到所有的请求上.。这包括诸如处理异常,重试失败的请求,记录分析信息或者可能实现缓存层来减少对于重度使用的 Http 调用流。

    对于熟悉 ASP.NET Core 的开发者,你可能也熟悉了中间件的概念。DelegatingHandler 提供了几乎相同的概念,但是是反过来的,是用于对外的请求。

    你可以定义一个处理器链作为管线,它可以在请求发出之前处理对外的请求,这些处理器可能会修改请求头,检查请求的内容或者记录关于请求的信息。

    HttpRequestMessage 依次流过每个处理器直到到达内部最终处理器。该处理器是实际发出 Http 请求。该内部的处理器也是第一个收到响应的处理器。此时,响应的内容依次以相反的顺序穿过处理器管线。又一次,每个处理器可以检查,修改或是根据需要使用响应内容。对于特定的请求你可能对响应的内容应用缓存。

    非常类似于 ASP.NET Core 中间件,处理器也可以短路过程并立即返回响应。一种情况是强制特定的规则,例如,你可以创建一个处理器来检查是否一个关键的请求头已经就绪。如果缺失了,就不需要将请求传递给下一个处理器 (避免实际的请求),相反,生成失败的响应以返回给掉用者。

    在 HttpClientFactory 和它的扩展之前,你可能需要手工传递处理器的实例到你的 HttpClient 实例的构造函数。该实例将通过这些处理器来处理实际的请求。

    通过 IHttpClientFactory ,我们可以更加便捷地应用一个或者多个处理器,在注册命名或者强类型的客户端的时候,可以定义它们。然后,我们通过 HttpClientFactory 获得的 HttpClient 任何实例,将被配置为使用这些管线,我们将通过代码演示这种方便的方式。

    DelegatingHandler 抽象类

    public abstract class DelegatingHandler : System.Net.Http.HttpMessageHandler
    {
      protected internal override System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken);
      protected override void Dispose (bool disposing);
    }
    

    创建处理器

    我们将定义两个处理器,为了保持代码简单,它不会实现实际的功能。它们将演示关键的概念,如在后继的文章中所示,达到类似的目的并不需要我们编写自己的处理器。

    为了创建处理器,我们可以简单地创建派生自 DelegatingHandler 抽象类的派生类。重写 SendAsync 方法来添加自己的功能。

    public class TimingHandler : DelegatingHandler
    {
        private readonly ILogger<TimingHandler> _logger;
    
        public TimingHandler(ILogger<TimingHandler> logger)
        {
            _logger = logger;
        }
    
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, 
            CancellationToken cancellationToken)
        {
            var sw = Stopwatch.StartNew();
    
            _logger.LogInformation("Starting request");
    
            var response = await base.SendAsync(request, cancellationToken);
    
            _logger.LogInformation($"Finished request in {sw.ElapsedMilliseconds}ms");
    
            return response;
        }
    }
    

    对于我们对外的请求,一个计时器将在开始调用之前开始,并等待底层处理器的 SendAsync() 方法返回 HttpResponseMessage。此时对外的请求完成,我们可以记录整个 Http 所花费的时间。

    为了更有趣一些,我们创建第二个处理器。它将检查是否存在特定的请求头,如果缺失,它将立即返回响应,短路处理器管线并避免不必要的 Http 调用。

    public class ValidateHeaderHandler : DelegatingHandler
    {
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            if (!request.Headers.Contains("X-API-KEY"))
            {
                return new HttpResponseMessage(HttpStatusCode.BadRequest)
                {
                    Content = new StringContent("You must supply an API key header called X-API-KEY")
                };
            }
    
            return await base.SendAsync(request, cancellationToken);
        }
    }
    

    注册处理器

    现在,我们已经创建了处理器并希望使用它们,最所的步骤是将它们注册到依赖注入容器中以定义客户端。我们在 Startup 类的 ConfigureServices() 方法中进行处理。

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddTransient<TimingHandler>();
        services.AddTransient<ValidateHeaderHandler>();
    
        services.AddHttpClient("github", c =>
        {
            c.BaseAddress = new Uri("https://api.github.com/");
            c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
            c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
        })
        .AddHttpMessageHandler<TimingHandler>() // This handler is on the outside and executes first on the way out and last on the way in.
        .AddHttpMessageHandler<ValidateHeaderHandler>(); // This handler is on the inside, closest to the request.
    }
    

    然后定义客户端,在示例中,我使用命名客户端进行简化,请查看本系列的上一博客来得到关于命名和类型化客户端的内容。 AddHttpClient() 方法此时返回一个 IHttpClientBuilder 对象。可以调用 builder 上增强的扩展方法,这里我们掉用范型的 AddHttpMessageHander() 方法。该方法以范型参数的形式使用处理器的类型。

    注册的顺序是有意义的。我们需要先注册最外层的处理器。该处理器将第一个检查请求,并最后看到响应。在本示例中,我们希望计时处理器能够统计整个请求所花费的时间,包括花费在内部处理器上的时间,所以我们首先添加该处理器。然后,我们再次掉用 AddHttpMessageHander() 方法,此时使用我们的 ValidateHeaderHandler 处理器,这是在哪瘦的 HttpClientHander 处理之前的最后一个处理器。

    现在我们构建了请求处理中间件管线来定义我们命名的 github 客户端。当请求通过该客户端的时候,它将首先到达 TimingHandler ,然后是 ValidateHeaderHandler。假设请求头存在于请求中,它将被传送并发出请求的 URI 地址上。当响应到达的时候,它首先通过 ValidateHeaderHandler,但它本身没有任何处理,然后,TimingHandler 将计算整个处理时间,最终返回给掉用代码。

    总结

    本文展示了使用新的扩展创建 DelegatingHandler 是如何容易,并添加到 HttpClient 处理管线中。不过并不希望你编写自己的处理器。Polly 第三方库可以处理常见的场景。

    Part 1 – HttpClientFactory in ASP.NET Core 2.1 Part 1 介绍
    Part 2 – HttpClientFactory in ASP.NET Core 2.1 Part 2:定义命名和类型化的客户端

    Part 3 – HttpClientFactory in ASP.NET Core 2.1 Part 3: 对处理器使用对外请求中间件
    Part 4 – HttpClientFacotry Part 4: 集成 Polly 处理瞬时失效
    Part 5 – HttpClientFactory in ASP.NET Core 2.1 Part 5: 日志

  • 相关阅读:
    求所有科目都大于80分的学生姓名
    sql server如何设置密码过期时间呢?
    sql server官网使用查找技术文档(msdn、联机丛书)
    【版本特性】sql server2014版本特性
    SQLSERVER文件组误脱机后如何联机
    sql server2014中的内存优化表/内存表(续写)
    JNI日志调试LOG和中文乱码
    JNI常见错误整理
    什么是“软解码”,什么又是“硬解码”呢?
    创建eclipse针对NDK的联合编译环境。
  • 原文地址:https://www.cnblogs.com/haogj/p/13807210.html
Copyright © 2020-2023  润新知