ASP.NET Core 2.2 基础知识(十二) 发送 HTTP 请求
可以注册 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 请求的更多相关文章
- ASP.NET Core 2.2 基础知识(十八) 托管和部署 概述
		为了方便演示,以 .NET Core 控制台应用程序讲解. 我们新建一个控制台应用程序,安装 "Newtonsoft.Json" Nuget 包,然后右键点击该项目,选择" ... 
- ASP.NET Core 2.2 基础知识(十六) SignalR 概述
		我一直觉得学习的最好方法就是先让程序能够正常运行,才去学习他的原理,剖析他的细节. 就好像这个图: 所以,我们先跟着官方文档,创建一个 SignalR 应用: https://docs.microso ... 
- ASP.NET Core 2.2 基础知识(十四) WebAPI Action返回类型(未完待续)
		要啥自行车,直接看手表 //返回基元类型 public string Get() { return "hello world"; } //返回复杂类型 public Person ... 
- ASP.NET Core 2.2 基础知识(十) Web服务器 - Kestrel
		ASP.NET Core 应用与进程内的 HTTP 服务器实现一起运行.该服务器实现侦听 HTTP 请求,并在一系列请求功能被写到 HttpContext 时,将这些请求展现到应用中. ASP.NET ... 
- ASP.NET Core 2.2 基础知识(十五) Swagger
		安装 Nuget 包 注册 Swagger public void ConfigureServices(IServiceCollection services) { services.AddMvc() ... 
- ASP.NET Core 2.2 基础知识(十一) ASP.NET Core 模块
		ASP.NET Core 应用与进程内的 HTTP 服务器实现一起运行.该服务器实现侦听 HTTP 请求,并在一系列请求功能被写到 HttpContext 时,将这些请求展现到应用中. ASP.NET ... 
- ASP.NET Core 2.2 基础知识(十三) WebAPI 概述
		我们先创建一个 WebAPI 项目,看看官方给的模板到底有哪些东西 官方给出的模板: [Route("api/[controller]")] [ApiController] pub ... 
- ASP.NET Core 2.2 基础知识(九) 使用托管服务实现后台任务
		在 ASP.NET Core 中,后台任务作为托管服务实现.托管服务是一个类,而且必须实现 IHostedService 接口,该接口定义了两个方法: StartAsync(CancellationT ... 
- ASP.NET Core 2.2 基础知识(八) 主机 (未完待续)
		主机负责应用程序启动和生存期管理.共有两个主机 API : 1.Web 主机 : 适用于托管 Web 应用,基于 IWebHostBuilder ; 2.通用主机 : 适用于托管非 Web 应用. 基 ... 
随机推荐
- [Leetcode] Binary tree maximum path sum求二叉树最大路径和
			Given a binary tree, find the maximum path sum. The path may start and end at any node in the tree. ... 
- 洛谷 P2894 [USACO08FEB]酒店Hotel 解题报告
			P2894 [USACO08FEB]酒店Hotel 题目描述 The cows are journeying north to Thunder Bay in Canada to gain cultur ... 
- 【BZOJ 2553】[BeiJing2011]禁忌 AC自动机+期望概率dp
			我一开始想的是倒着来,发现太屎,后来想到了一种神奇的方法——我们带着一个既有期望又有概率的矩阵,偶数(2*id)代表期望,奇数(2*id+1)代表概率,初始答案矩阵一列,1的位置为1(起点为0),工具 ... 
- java一个接口可以继承另外一个接口吗
			一个接口可以继承多个接口. interface C extends A, B {}是可以的. 一个类可以实现多个接口: class D implements A,B,C{} 但是一个类只能继承一个类, ... 
- 如何最快地实现 ALTER TABLE
			如果您不了解ALTER TABLE的语法,可以先参考: http://dev.mysql.com/doc/refman/5.1/en/alter-table.html 使用ALTER TABLE 可以 ... 
- 最小k度最小生成树模板
			代码是抄的 题解是瞄的 可我想学习的心是真的嘤嘤嘤 然而 还是上传一份ioi大神的论文吧 链接:https://pan.baidu.com/s/1neIW9QeZEa0hXsUqJTjmeQ 密码:b ... 
- angular js的Inline Array Annotation的理解
			inline Array annotation的形式是: someModule.controller('MyController', ['$scope', 'greeter', function($s ... 
- java的GC与内存泄漏
			从诞生至今,20多年过去,Java至今仍是使用最为广泛的语言.这仰赖于Java提供的各种技术和特性,让开发人员能优雅的编写高效的程序.今天我们就来说说Java的一项基本但非常重要的技术内存管理 了解C ... 
- js 禁止鼠标和键盘行为
			<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ... 
- 教主泡嫦娥(RQNOJ 595)
			题目描述 [问题背景] 2012年12月21日下午3点14分35秒,全世界各国的总统以及领导人都已经汇聚在中国的方舟上. 但也有很多百姓平民想搭乘方舟,毕竟他们不想就这么离开世界,所以他们决定要么登上 ... 
