.Net Core 2.1 使用Http请求及基于 Polly 的处理故障

时间:2022-03-11 12:37:56

一、介绍

  在IServiceCollection调用AddHttpClient注册IHttpClientFactory服务,调用AddHttpMessageHandler以生成出站请求中间件管道。 每个处理程序都可以在出站请求前后执行工作。通过Polly 的处理程序,以表达策略处理重试、断路器、超时、隔离和回退。

二、使用http请求

1.配置注册

var host = new HostBuilder()
      .ConfigureServices((context, services) => {
            services.AddHttpClient();
            services.AddHostedService<MyHostedService>();
      })
      .UseConsoleLifetime()
      .Build();

2.请求的后台服务

public Task StartAsync(CancellationToken cancellationToken)
        {
            return Task.Run(async () =>
            {
                var request = new HttpRequestMessage(HttpMethod.Post, "http://www.baidu.com");
                request.Headers.Add("Accept", "application/json");//设置请求头
                request.Properties.Add("id","123");//设置请求参数
                var client = _clientFactory.CreateClient();
                var response = await client.SendAsync(request);
                string result = null;
                if (response.IsSuccessStatusCode)
                {
                    result = await response.Content.ReadAsStringAsync();
                }
            });
        }

 3.执行时控制台输入日志

.Net Core 2.1 使用Http请求及基于 Polly 的处理故障

二、以客户端的方式使用

在客户端中配置,默认请求Url地址和默认的header。

public class HaosRequestService
    {
        public HttpClient Client { get; }

        public HaosRequestService(HttpClient client)
        {
            //配置默认值
            client.BaseAddress = new Uri("http://www.baidu.com/");
            client.DefaultRequestHeaders.Add("Accept","application/json");
            Client = client;
        }
        /// <summary>
        /// 封装常用方法
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<string> SeachAsync(string key)
        {
            var content = new FormUrlEncodedContent(new[] {
                new KeyValuePair<string,string>("w","关键字"),
            });
            var response = await Client.PostAsync("/s",content);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsStringAsync();
        }
    }

在IServiceCollection中注册

var host = new HostBuilder()
                .ConfigureServices((context, services) => {
                    services.AddHttpClient<HaosRequestService>();
                    services.AddHostedService<MyHostedService>();
                })

三、处理出站 HTTP 请求

 IHttpClientFactory 可以为客户端定义处理程,支持注册和链接多个处理程序。要创建处理程序,先定义一个继承 DelegatingHandler 的类。 重写 SendAsync 方法,在将请求传递至管道中的下一个处理程序之前

 

using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace Haos.Develop.HttpRequest.Samples
{
    public class ColationDelegatingHandler:DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            //此处实现过滤逻辑
            return base.SendAsync(request, cancellationToken);
        }
    }
}

 

var Host = new HostBuilder()
    .ConfigureAppConfiguration(builder =>
    {
        builder.AddCommandLine(args);
    })
    .ConfigureServices((context, services) =>
    {
        services.AddHttpClient<RequestClient>()
        //注册过滤程序
        .AddHttpMessageHandler<ColationDelegatingHandler>();
    })
    .UseConsoleLifetime()
    .Build();

 

四、基于Polly的处理程序

  Polly 以表达策略,例如以流畅且线程安全的方式处理重试、断路器、超时、Bulkhead 隔离和回退。Microsoft.Extensions.Http.Polly NuGet 包中提供 Polly 扩展实现将 Polly 策略用于配置的 HttpClient 实例。 

  Polly 添加策略分为三种

    1. AddTransientHttpErrorPolicy:是处理Http请求的错误,如HTTP 5XX 的状态码,HTTP 408 的状态码 以及System.Net.Http.HttpRequestException异常

    2. AddPolicyHandler:添加自定义策列

    3. AddPolicyHandlerFromRegistry:从Policy注册表集合里面选择添加

  a. AddTransientHttpErrorPolicy

.ConfigureServices((context, services) =>
{
    services.AddHttpClient<RequestClient>()
    .AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(3, t => TimeSpan.FromMilliseconds(500)))
    //或。上下都是定义了,错误重试上面是间隔都是500毫秒,下面则定义了每次重试的时间间隔
    .AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[] {
        TimeSpan.FromSeconds(1),
        TimeSpan.FromSeconds(5),
        TimeSpan.FromSeconds(10)
    }));
})

  b. AddPolicyHandler

  先定义策略,在通过AddPolicyHandler方法添加,改方法接收一个泛型的IAsyncPolicy<HttpResponseMessage>。HttpResponseMessage我理解为出站请求上下文

.ConfigureServices((context, services) =>
{
    var retryPolicy = Policy.Handle<HttpRequestException>()
    .OrResult<HttpResponseMessage>(response => {
        //此处实现处理改异常的逻辑
        return true;
    }).WaitAndRetryAsync(3,t => TimeSpan.FromMilliseconds(50));

    services.AddHttpClient<RequestClient>()
    .AddPolicyHandler(retryPolicy);
})
retryPolicy:发生HttpRequestException的异常,并且OrResult返回结果为true,采用这个策略

  c. AddPolicyHandlerFromRegistry

  先注册策略表服务,为策略表添加策略,最后通过AddPolicyHandlerFromRegistry方法选用某个或几个策略

.ConfigureServices((context, services) =>
{
    //注册,策略表服务
    var registry = services.AddPolicyRegistry();
    //创建策略
    var retryPolicy = Policy.Handle<HttpRequestException>()
    .OrResult<HttpResponseMessage>(response => {
        //此处实现处理改异常的逻辑
        return true;
    }).WaitAndRetryAsync(3, t => TimeSpan.FromMilliseconds(50));
    registry.Add("registry1", retryPolicy);
    services.AddHttpClient<RequestClient>()
    .AddPolicyHandlerFromRegistry("registry1");
})

  添加多个 Polly 处理程序嵌套 Polly 策略以增强功

    分别定义三种策略,timeoutPolicy,noOpPolicy,retryPolicy 通过策略表的方式和自定义。添加多个策略。

.ConfigureServices((context, services) =>
{
    //注册,策略表服务
    var registry = services.AddPolicyRegistry();
    //创建策略
    var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(10);//10秒超时
    var noOpPolicy = Policy.NoOpAsync().AsAsyncPolicy<HttpResponseMessage>();//有时我们也需要一个没有任何行为的策略,Polly系统默认提供了一个.
    var retryPolicy = Policy.Handle<HttpRequestException>()
    .OrResult<HttpResponseMessage>(response => {
        //此处实现处理改异常的逻辑
        return true;
    }).WaitAndRetryAsync(3, t => TimeSpan.FromMilliseconds(50));
    registry.Add("registry1", retryPolicy);
    registry.Add("registry2", timeoutPolicy);
    services.AddHttpClient<RequestClient>()
    .AddPolicyHandlerFromRegistry("registry1")
    .AddPolicyHandler(retryPolicy)
    .AddPolicyHandler(timeoutPolicy);
})