继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

ASP.NET Core 2.2 基础知识(十二) 发送 HTTP 请求

湖上湖
关注TA
已关注
手记 276
粉丝 85
获赞 377

可以注册 IHttpClientFactory 并将其用于配置和创建应用中的 HttpClient 实例。 这能带来以下好处:

  • 提供一个中心位置,用于命名和配置逻辑 HttpClient 实例。 例如,可以注册 github 客户端,并将它配置为访问 GitHub。 可以注册一个默认客户端用于其他用途。

  • 通过委托 HttpClient 中的处理程序整理出站中间件的概念,并提供适用于基于 Polly 的中间件的扩展来利用概念。

  • 管理基础 HttpClientMessageHandler 实例的池和生存期,避免在手动管理 HttpClient 生存期时出现常见的 DNS 问题。

  • (通过 ILogger)添加可配置的记录体验,以处理工厂创建的客户端发送的所有请求。

在应用中可以通过以下多种方式使用 IHttpClientFactory

基本用法

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);            services.AddHttpClient();
        }

 

复制代码

    [Route("api/[controller]")]
    [ApiController]    public class ValuesController : ControllerBase
    {        private readonly IHttpClientFactory _clientFactory;        public ValuesController(IHttpClientFactory clientFactory)
        {
            _clientFactory = clientFactory;
        }        // GET api/values        [HttpGet]        public async Task<string> Get()
        {
            HttpClient client = _clientFactory.CreateClient();            //方法一:            //HttpRequestMessage request = new HttpRequestMessage            //{            //    Method = new HttpMethod("get"),            //    RequestUri = new System.Uri("http://localhost:5000/api/values"),            //};            //HttpResponseMessage response = await client.SendAsync(request);            //string res = await response.Content.ReadAsStringAsync();            //return res;            //方法二:
            string res = await client.GetStringAsync("http://localhost:5000/api/values");            return res;
        }
     }

复制代码

 

命名客户端

复制代码

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);            services.AddHttpClient("test", c =>
            {
                c.BaseAddress = new Uri("http://localhost:5000");
            });
        }

复制代码

 

复制代码

        public async Task<string> Get()
        {
            HttpClient client = _clientFactory.CreateClient("test");            //注册名叫 "test" 的客户端时,已经指定了该客户端的请求基地址,所以这里不需要指定主机名了
            return await client.GetStringAsync("api/values");
        }

复制代码

 

类型化客户端

复制代码

    public class TestHttpClient
    {        public HttpClient Client { get; set; }        public TestHttpClient(HttpClient client)
        {
            client.BaseAddress = new System.Uri("http://localhost:5000");
            Client = client;
        }        public async Task<string> Get()
        {            return await Client.GetStringAsync("api/values");
        }
    }

复制代码

 

复制代码

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddHttpClient<TestHttpClient>(c =>
            {                //可以在这里设置,也可以在构造函数设置.                //c.BaseAddress = new System.Uri("http://localhost:5000");            });
        }

复制代码

 

复制代码

    [Route("api/[controller]")]
    [ApiController]    public class ValuesController : ControllerBase
    {        private readonly TestHttpClient _client;        public ValuesController(TestHttpClient client)
        {
            _client = client;
        }             [HttpGet]        public async Task<string> Get()
        {            return await _client.Get();
        }
    }

复制代码

 

出站请求中间件

HttpClient 已经具有委托处理程序的概念,这些委托处理程序可以链接在一起,处理出站 HTTP 请求。 IHttpClientFactory 可以轻松定义处理程序并应用于每个命名客户端。 它支持注册和链接多个处理程序,以生成出站请求中间件管道。 每个处理程序都可以在出站请求前后执行工作。 此模式类似于 ASP.NET Core 中的入站中间件管道。 它提供了一种用于管理围绕 HTTP 请求的横切关注点的机制,包括缓存、错误处理、序列化以及日志记录。

要创建处理程序,需要定义一个派生自 DelegatingHandler 的类。 重写 SendAsync 方法,在将请求传递至管道中的下一个处理程序之前执行代码:

复制代码

    public class ValidateHeaderHandler : DelegatingHandler
    {        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {            if (!request.Headers.Contains("refuge"))
            {                return new HttpResponseMessage(HttpStatusCode.BadRequest)
                {
                    Content = new StringContent("not found refuge")
                };
            }            return await base.SendAsync(request, cancellationToken);
        }
    }

复制代码

 

复制代码

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);            services.AddTransient<ValidateHeaderHandler>();//生存期必须是临时
            services.AddHttpClient("test", c =>
                {
                    c.BaseAddress = new Uri("http://localhost:5000");
                })
                .AddHttpMessageHandler<ValidateHeaderHandler>();
        }

复制代码

 

HttpClient 和生存期管理

每次对 IHttpClientFactory 调用 CreateClient 都会返回一个新 HttpClient 实例:

复制代码

        public IEnumerable<int> Get()
        {            //测试生存期
            for (int i = 0; i < 4; i++)
            {
                HttpClient client = i % 2 == 0
                    ? _clientFactory.CreateClient("test")
                    : _clientFactory.CreateClient();                yield return client.GetHashCode();
            }
        }

复制代码

 

 

CreateClient 方法内部会调用 CreateHandler 方法,后者创建 HttpMessageHandler,

源码如下:

复制代码

    public HttpClient CreateClient(string name)
    {      if (name == null)        throw new ArgumentNullException(nameof (name));
      HttpClient httpClient = new HttpClient(this.CreateHandler(name), false);
      HttpClientFactoryOptions clientFactoryOptions = this._optionsMonitor.Get(name);      for (int index = 0; index < clientFactoryOptions.HttpClientActions.Count; ++index)
        clientFactoryOptions.HttpClientActions[index](httpClient);      return httpClient;
    }

复制代码

 

复制代码

    public HttpMessageHandler CreateHandler(string name)
    {      if (name == null)        throw new ArgumentNullException(nameof (name));
      ActiveHandlerTrackingEntry entry = this._activeHandlers.GetOrAdd(name, this._entryFactory).Value;      this.StartHandlerEntryTimer(entry);      return (HttpMessageHandler) entry.Handler;
    }

复制代码

 

而这个 _activeHandlers 的类型是 : 

一个线程安全的键值对集合.

因此,实际上创建的 HttpMessageHandler 实例会汇集到池中.新建 HttpClient 实例时,可能会重用池中的 HttpMessageHandler 实例(如果生存期尚未到期的话). 

由于每个处理程序通常管理自己的基础 HTTP 连接,因此需要池化处理程序.创建超出必要数量的处理程序可能会导致连接延迟. 部分处理程序还保持连接无期限地打开,这样可以防止处理程序对 DNS 更改作出反应.

处理程序的默认生存期为两分钟,可在每个命名客户端上重写默认值:

services.AddHttpClient("test").SetHandlerLifetime(TimeSpan.FromMinutes(5));

 

配置 HttpMessageHandler

有时候,我们需要控制客户端使用的内部 HttpMessageHandler .

            services.AddHttpClient("test")
                .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler()
                {
                    AllowAutoRedirect = false,
                });

原文出处:https://www.cnblogs.com/refuge/p/10230795.html  

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP