可以注册 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 = ; i < ; i++)
{
HttpClient client = i % ==
? _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 = ; 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());

配置 HttpMessageHandler

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

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

ASP.NET Core 2.2 基础知识(十二) 发送 HTTP 请求的更多相关文章

  1. ASP.NET Core 2.2 基础知识(十八) 托管和部署 概述

    为了方便演示,以 .NET Core 控制台应用程序讲解. 我们新建一个控制台应用程序,安装 "Newtonsoft.Json" Nuget 包,然后右键点击该项目,选择" ...

  2. ASP.NET Core 2.2 基础知识(十六) SignalR 概述

    我一直觉得学习的最好方法就是先让程序能够正常运行,才去学习他的原理,剖析他的细节. 就好像这个图: 所以,我们先跟着官方文档,创建一个 SignalR 应用: https://docs.microso ...

  3. ASP.NET Core 2.2 基础知识(十四) WebAPI Action返回类型(未完待续)

    要啥自行车,直接看手表 //返回基元类型 public string Get() { return "hello world"; } //返回复杂类型 public Person ...

  4. ASP.NET Core 2.2 基础知识(十) Web服务器 - Kestrel

    ASP.NET Core 应用与进程内的 HTTP 服务器实现一起运行.该服务器实现侦听 HTTP 请求,并在一系列请求功能被写到 HttpContext 时,将这些请求展现到应用中. ASP.NET ...

  5. ASP.NET Core 2.2 基础知识(十五) Swagger

    安装 Nuget 包 注册 Swagger public void ConfigureServices(IServiceCollection services) { services.AddMvc() ...

  6. ASP.NET Core 2.2 基础知识(十一) ASP.NET Core 模块

    ASP.NET Core 应用与进程内的 HTTP 服务器实现一起运行.该服务器实现侦听 HTTP 请求,并在一系列请求功能被写到 HttpContext 时,将这些请求展现到应用中. ASP.NET ...

  7. ASP.NET Core 2.2 基础知识(十三) WebAPI 概述

    我们先创建一个 WebAPI 项目,看看官方给的模板到底有哪些东西 官方给出的模板: [Route("api/[controller]")] [ApiController] pub ...

  8. ASP.NET Core 2.2 基础知识(九) 使用托管服务实现后台任务

    在 ASP.NET Core 中,后台任务作为托管服务实现.托管服务是一个类,而且必须实现 IHostedService 接口,该接口定义了两个方法: StartAsync(CancellationT ...

  9. ASP.NET Core 2.2 基础知识(八) 主机 (未完待续)

    主机负责应用程序启动和生存期管理.共有两个主机 API : 1.Web 主机 : 适用于托管 Web 应用,基于 IWebHostBuilder ; 2.通用主机 : 适用于托管非 Web 应用. 基 ...

随机推荐

  1. number 解题报告

    number 题目描述 给定整数 \(m,k\),求出正整数 \(n\) 使得 \(n+1,n+2,-,2n\) 中恰好有 \(m\) 个数在二进制下恰好有 \(k\) 个 \(1\). 有多组数据. ...

  2. 【bzoj2038】[国家集训队2010]小Z的袜子 莫队

    莫队:就是一坨软软的有弹性的东西Duang~Duang~Duang~ 为了防止以左端点为第一关键字以右端点为第二关键字使右端点弹来弹去,所以让左端点所在块为关键字得到O(n1.5)的时间效率,至于分块 ...

  3. Android-使用ViewFlipper实现轮番切换广告栏

    所谓的轮番切换广告栏,指的是下面这个东西,笔主不知道该怎么确切描述这货... 笔主没有百度研究过其他大牛是怎么实现这个功能的,在这里笔主充分发挥DIY精神,利用ViewFlipper闭门土制了一个,下 ...

  4. IDEA新建时选项没有java class问题

    解决办法: 点击你的project F4打开project stucture 点击左边的module 点击右边的source后添加src就可以了  添加的src就是源码可以放置的地址

  5. 文本区 JTextArea 的使用

    文本区JTextArea是对多行文本进行编辑的组件,用空字符来控制文本的格式.eg:"\n"为换行,"\t"为插入一个Tab字符. 文本去JTextArea的常 ...

  6. webstorm vue代码修改后不更新问题

    把 safe write 的勾去掉就行了.

  7. elasticsearch.helpers.ScanError: Scroll request has only succeeded on xx shards

    # 当index=''为空时出现此错误

  8. 关于gsl库出现access violation 0X00000005问题的解决方法

    gsl即GNU SCIENCE LIBRARY是一个强大c/c++的数值计算函数库. 在使用这一库出现access violation 0X00000005问题,尝试方法一在project->C ...

  9. HDU1907(尼姆博弈)

    John Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submis ...

  10. linux中链表的使用【转】

    转自:http://blog.csdn.net/finewind/article/details/8074990 Linux下链表的使用方法跟我们常规的不一样,通常情况下,链表的next指针都指向节点 ...