.NET Core 中正确使用 HttpClient 的姿势
为了更方便在服务端调用 HTTP 请求,微软在 .NET Framework 4.x 的时候引入了 HttpClient。但 HttpClient 有很多严重问题,一直饱受诟病,比如 InfoQ 的这篇文章 t.cn/Evzy80y,吐槽了 HttpClient 不能立即关闭连接、性能消耗严重等的问题。
.NET Core 2.1 开始引入的 HttpClientFactory 解决了 HttpClient 的所有痛点。有了 HttpClientFactory,我们不需要关心如何创建 HttpClient,又如何释放它。通过它可以创建具有特定业务的 HttpClient,而且可以很友好的和 DI 容器结合使用,更为灵活。下面以 ASP.NET Core 为例介绍 HttpClient 新的三种正确使用方式。
一、直接使用方式
不管是哪种方式,都要先注册服务,对于 ASP.NET Core 应用则是在 Startup.cs
文件的 ConfigureServices
添加如果代码:
services.AddHttpClient();
然后在 Controller 中通过构造注入的试获得 IHttpClientFactory
,然后通过它来创建 HttpClient 对象。示例代码:
public class ValuesController : BaseController
{
private readonly IHttpClientFactory _httpClientFactory;
public ValuesController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
[HttpGet]
public async Task<ActionResult> Get()
{
var client = _httpClientFactory.CreateClient();
client.BaseAddress = new Uri("http://api.github.com");
string result = await client.GetStringAsync("/");
return Ok(result);
}
}
这种使用方式适合一次性的 HTTP 请求调用,弊端是如果多次都要请求 github 的接口,那就得写很多重复代码配置 HttpClient。
二、命名式使用方式
命名式的使用方式可以解决第一种方式的问题,对于特定域名的 HTTP 调用,可以只做一次配置,然后在多个地方通过名称拿到相同的 Client 来使用。
首先在 Startup.cs
注册服务的地方添加带有特定名称的 HttpClient 服务,并添加需要的配置,如下示例:
services.AddHttpClient();
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");
});
注意这里添加了两次 AddHttpClient
,一次是没有命名的,一次是有命名的。在 Controller 中的使用方式是:
public class ValuesController : BaseController
{
private readonly IHttpClientFactory _httpClientFactory;
public ValuesController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
[HttpGet]
public async Task<ActionResult> Get()
{
var client = _httpClientFactory.CreateClient("github");
string result = await client.GetStringAsync("/");
return Ok(result);
}
}
但如果使用很频繁,这种获取 Client 的方式还是有一点麻烦。下面介绍第三种方式,可以在使用的时候方便一点,但配置要麻烦些。
三、类型化使用方式
类型化的使用方式可以预先把配置放到自定义的 HttpClient 中,然后在需要的地方都过依赖注入直接拿到 HttpClient 实例。
我们来看具体的例子,首先自定义一个 HttClient 类,比如访问 github 接口的类可以这样定义:
public class GitHubClient
{
public HttpClient Client { get; private set; }
public GitHubClient(HttpClient httpClient)
{
httpClient.BaseAddress = new Uri("https://api.github.com/");
httpClient.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
httpClient.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
Client = httpClient;
}
public async Task<string> GetData()
{
return await _client.GetStringAsync("/");
}
}
这里的 GetData
就是额外扩展的共用方法。使用前需要为这个类注册服务:
services.AddHttpClient<GitHubClient>();
然后在需要的地方(比如 Controller)中这样使用:
public class ValuesController : BaseController
{
private readonly GitHubClient _gitHubClient;;
public ValuesController(GitHubClient gitHubClient)
{
_gitHubClient = gitHubClient;
}
[HttpGet]
public async Task<ActionResult> Get()
{
string result = await _gitHubClient.GetData();
return Ok(result);
}
}
类型化的方式和命名式的方式相比,虽然在配置的时候会麻烦一点,但它有两个好处:一是不用通过名称字符串来获得 Client,而是直接通过依赖注入获得具体的 Client;二是可以在自定义的 HttpClient 类中扩展共用的方法。
.NET Core 中正确使用 HttpClient 的姿势的更多相关文章
- iOS中正确的截屏姿势
昨天写了个用到截屏功能的插件,结果问题不断,今天终于解决好了,把debug过程中所有尝试过的截屏方法都贴出来吧- 第一种 这是iOS 3时代开始就被使用的方法,它被废止于iOS 7.iOS的私有方法, ...
- .NET Core 中读取 Request.Headers 的姿势
Request.Headers 的类型是 IHeaderDictionary 接口,对应的实现类是 HeaderDictionary ,C# 实现源码见 HeaderDictionary.cs . H ...
- 在 .NET Core 中结合 HttpClientFactory 使用 Polly(下篇)
译者:王亮作者:Polly 团队原文:http://t.cn/EhZ90oq声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的(包括标题).其中可能会去除一些不影响理解但本人实在不知道如 ...
- 在 .NET Core 中结合 HttpClientFactory 使用 Polly(中篇)
译者:王亮作者:Polly 团队原文:http://t.cn/EhZ90oq声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的(包括标题).其中可能会去除一些不影响理解但本人实在不知道如 ...
- 在 .NET Core 中结合 HttpClientFactory 使用 Polly(上篇)
译者:王亮作者:Polly 团队原文:http://t.cn/EhZ90oq 译者序一:前两天写了一篇文章 .NET Core 开源项目 Polly 介绍,在写这篇文章查看 Polly 资料时,看到了 ...
- ASP.NET Core中如何针对一个使用HttpClient对象的类编写单元测试
原文地址: How to unit test a class that consumes an HttpClient with IHttpClientFactory in ASP.NET Core? ...
- HttpClient在.NET Core中的正确打开方式
问题来源 长期以来,.NET开发者都通过下面的方式发送http请求: using (var httpClient = new HttpClient()) { var response = await ...
- ASP.NET Core 中读取 Request.Body 的正确姿势
ASP.NET Core 中的 Request.Body 虽然是一个 Stream ,但它是一个与众不同的 Stream —— 不允许 Request.Body.Position=0 ,这就意味着只能 ...
- Asp.Net Core 单元测试正确姿势
背景 ASP.NET Core 支持依赖关系注入 (DI) 软件设计模式,并且默认注入了很多服务,具体可以参考 官方文档, 相信只要使用过依赖注入框架的同学,都会对此有不同深入的理解,在此无需赘言. ...
随机推荐
- GitHub Flow & Git Flow 基于Git 的两种协作开发模式
介绍基于Git 两种协作开发模式,GitHub Flow & Git Flow 对于Github 一些好用的特殊操作技巧 ,可以见GitHub 特殊操作技巧 和Git的基本操作 一 GitHu ...
- ASP.NET Core 应用发布与部署指南
一.前言 本篇主要包含哪些内容? 将项目发布到本地目录 将项目传输到服务器并配置启动&开机自动启动 将Nginx作为访问入口,配置反向代理 本篇环境信息 开发环境: 用途 工具&版本 ...
- 作为IT,你的价值在哪里?
也许最近是真的被无穷无尽的数据整理.导入.再整理.再导入给恶心到了. 业务部提交的数据只是一个非常初始的数据,IT还得在这个基础上七整八整,对导出的结果还要再做二次导入三次导入,不仅要帮业务部批导生成 ...
- 服务器CPU繁忙或内存压力引起网络掉包的浅析与总结
最近一段时间遇到了两起有意思的故障,现象都是网络掉包或网络断开,不过这些只是表面现象,引起现象出现的本质才是我们需要关注的重点: 案例1: 平台 :VMware平台 操作系统 :Windows ...
- sql 语句按字段指定值排序及分页
为特定字段赋值并排序 表[Table_temp]中列[col1]为字符,属性为varchar(),排序时需要按照B.A.C的顺序显示,则可按照以下SQL语句: select * from Table_ ...
- 两层c:forEach循环嵌套
jsp中两级菜单如何用c:forEach输出 items 要被循环的信息 否 无 begin 开始的元素(0=第一个元素,1=第二个元素) 否 0 end 最后一个元素(0=第一个元素,1=第二个元素 ...
- CVE-2017-8464 分析
目录 CVE-2017-8464(stuxnet 3.0) 分析 0xFF 前言 0x00 分析工具 0x01 漏洞复现 1).生成一个DLL用于测试 2).构造一个恶意的lnk二进制文件 3).RU ...
- 类中的 this关键字
this可用于区分局部变量和成员变量,因为构造函数中如果使用 this.成员变量 = 参数值, 那么可以在new对象时,将初始化值赋值给成员变量,否则成员变量赋值失败, 所以this可以区分成员变量和 ...
- Python爬虫-04:贴吧爬虫以及GET和POST的区别
目录 1. URL的组成 2. 贴吧爬虫 2.1. 只爬贴吧第一页 2.2. 爬取所有贴吧的页面 3. GET和POST的区别 3.1. GET请求 3.2. POST请求 3.3. 有道翻译模拟发送 ...
- DbContext 和 ObjectContext两者的区别
ObjectContext是一种模型优先的开发模式,DbContext是代码优先的开发模式.这是两者最根本的区别. 同时两者之间可以相互转换: 下面给出转换的例子 1.DbContext转为Objec ...