一、HTTP系列演进

方式 说明
HttpWebRequest .NET早期版本,同步方式
WebClient HttpWebRequest的封装简化版,同步方式
HttpClient .NET4.5以后,异步方式
HttpClientFactory .NET Core2.1

二、HttpClient用法

HttpClient 提供的方法:

 GetAsync(String) 	//以异步操作将GET请求发送给指定的URI
GetAsync(URI) //以异步操作将GET请求发送给指定的URI
GetAsync(String, HttpCompletionOption) //以异步操作的HTTP完成选项发送GET请求到指定的URI
GetAsync(String, CancellationToken) //以异步操作的取消标记发送GET请求到指定URI
GetAsync(Uri, HttpCompletionOption) //以异步操作的HTTP完成选项发送GET请求到指定的URI
GetAsync(Uri, HttpCompletionOption, CancellationToken) //以异步操作的HTTP完成选项和取消标记发送DELETE请求到指定的URI
GetAsync(Uri, HttpCompletionOption, CancellationToken) //以异步操作的HTTP完成选项和取消标记发送DELETE请求到指定的URI
GetByteArrayAsync(String) //将GET请求发送到指定URI并在异步操作中以字节数组的形式返回响应正文
GetByteArrayAsync(Uri) //将GET请求发送到指定URI并在一异步操作中以字节数组形式返回响应正文
GetHashCode //用作特定类型的哈希函数,继承自Object
GetStreamAsync(String) //将GET请求发送到指定URI并在异步操作中以流的形式返回响应正文
GetStreamAsync(Uri) //将GET请求发送到指定URI并在异步操作以流的形式返回响应正文
GetStreamAsync(String) //将GET请求发送到指定URI并在异步操作中以字符串的形式返回响应正文
GetStringAsync(Uri) //将GET请求发送到指定URI并在异步操作中以字符串形式返回响应正文
using(var httpClient = new HttpClient())
{
//other codes
}

以上用法是不推荐的,HttpClient 这个对象有点特殊,虽然继承了 IDisposable 接口,但它是可以被共享的(或者说可以被复用),且线程安全。从项目经验来看,推荐在整个应用的生命周期内复用 HttpClient 实例,而不是每次RPC请求的时候就实例化一个,在高并发的情况下,会造成Socket资源的耗尽。

示例1:

public class Program
{
private static readonly HttpClient _httpClient = new HttpClient();
static void Main(string[] args)
{
HttpAsync();
Console.WriteLine("Hello World!");
Console.Read();
}
public static async void HttpAsync()
{
for (int i = 0; i < 10; i++)
{
var result = await _httpClient.GetAsync("http://www.baidu.com");
Console.WriteLine($"{i}:{result.StatusCode}");
}
}
}

示例2:

public async Task<string> GetAccessTokenAsync()
{
string uri = "你的URL";
HttpClientHandler handler = new HttpClientHandler
{
//设置是否发送凭证信息,有的服务器需要验证身份,不是所有服务器需要
UseDefaultCredentials = false
};
HttpClient httpClient = new HttpClient(handler);
HttpResponseMessage response = await httpClient.GetAsync(uri);
response.EnsureSuccessStatusCode();
//回复结果直接读成字符串
string resp = await response.Content.ReadAsStringAsync();
JObject json = (JObject)JsonConvert.DeserializeObject(resp);
string accessToken = json["access_token"].ToString();
//采用流读数据
//using (Stream streamResponse = await response.Content.ReadAsStreamAsync())
//{
// StreamReader reader = new StreamReader(streamResponse);
// string responseFromServer = reader.ReadToEnd();
// JObject res = (JObject)JsonConvert.DeserializeObject(responseFromServer);
// accessToken = res["access_token"].ToString();
// reader.Close();
//}
//获得许可证凭证
PostMailAsync(accessToken);
//关闭响应
return "success";
}

优化:帮HttpClient预热

我们采用一种预热方式,在正式发post请求之前,先发一个head请求:

_httpClient.SendAsync(new HttpRequestMessage {
Method = new HttpMethod("HEAD"),
RequestUri = new Uri(BASE_ADDRESS + "/")
})
.Result.EnsureSuccessStatusCode();

经测试,通过这种热身方法,可以将第一次请求的耗时由2s左右降到1s以内(测试结果是700多ms)。

存在问题

复用 HttpClient 后,依然存在一些问题:

  1. 因为是复用的 HttpClient ,那么一些公共的设置就没办法灵活的调整了,如请求头的自定义。
  2. 因为 HttpClient 请求每个 url 时,会缓存该 url 对应的主机 ip ,从而会导致 DNS 更新失效( TTL 失效了)

那么有没有办法解决HttpClient的这些个问题?直到 HttpClientFactory 的出现,这些坑 “完美” 规避掉了。

三、HttpClientFactory

  • HttpClientFacotry 很高效,可以最大程度上节省系统 socket 。(“JUST USE IT AND FXXK SHUT UP”)
  • Factory,顾名思义 HttpClientFactory 就是 HttpClient 的工厂,内部已经帮我们处理好了对 HttpClient 的管理,不需要我们人工进行对象释放,同时,支持自定义请求头,支持DNS更新等等等。
  • 从微软源码分析,HttpClient 继承自 HttpMessageInvoker ,而 HttpMessageInvoker 实质就是 HttpClientHandler 。
  • HttpClientFactory 创建的 HttpClient ,也即是 HttpClientHandler ,这些个 HttpClient 被放到了“池子”中,工厂每次在 create 的时候会自动判断是新建还是复用。(默认生命周期为 2 min)

示例1

  1. 在 Startup.cs 中进行注册
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
//other codes
services.AddHttpClient("client_1", config => //这里指定的 name=client_1 ,可以方便我们后期复用该实例
{
config.BaseAddress = new Uri("http://client_1.com");
config.DefaultRequestHeaders.Add("header_1", "header_1");
});
services.AddHttpClient("client_2", config =>
{
config.BaseAddress = new Uri("http://client_2.com");
config.DefaultRequestHeaders.Add("header_2", "header_2");
});
services.AddHttpClient();
//other codes
services.AddMvc().AddFluentValidation();
}
}
  1. 使用,这里直接以 controller 为例,其他地方自行 DI
public class TestController : ControllerBase
{
private readonly IHttpClientFactory _httpClient;
public TestController(IHttpClientFactory httpClient)
{
_httpClient = httpClient;
}
public async Task<ActionResult> Test()
{
var client = _httpClient.CreateClient("client_1"); //复用在 Startup 中定义的 client_1 的 httpclient
var result = await client.GetStringAsync("/page1.html");
var client2 = _httpClient.CreateClient(); //新建一个 HttpClient
var result2 = await client.GetStringAsync("http://www.site.com/XXX.html");
return null;
}
}

示例2:使用自定义类执行 HttpClientFactory 请求

  1. 自定义 HttpClientFactory 请求类
public class SampleClient
{
public HttpClient Client { get; private set; }
public SampleClient(HttpClient httpClient)
{
httpClient.BaseAddress = new Uri("https://api.SampleClient.com/");
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
httpClient.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
Client = httpClient;
}
}
  1. 在 Startup.cs 中 ConfigureService 方法中注册 SampleClient
services.AddHttpClient<SampleClient>();
  1. 调用:
public class ValuesController : Controller
{
private readonly SampleClient _sampleClient;
public ValuesController(SampleClient sampleClient)
{
_sampleClient = sampleClient;
}
[HttpGet]
public async Task<ActionResult> Get()
{
string result = await _sampleClient.client.GetStringAsync("/");
return Ok(result);
}
}

示例3:完全封装 HttpClient 可以使用下面方法

  1. 自定义 HttpClientFactory 请求类
public interface ISampleClient
{
Task<string> GetData();
} public class SampleClient : ISampleClient
{
private readonly HttpClient _client;
public SampleClient(HttpClient httpClient)
{
httpClient.BaseAddress = new Uri("https://api.SampleClient.com/");
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
httpClient.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
_client = httpClient;
}
public async Task<string> GetData()
{
return await _client.GetStringAsync("/");
}
}
  1. 在Startup.cs中ConfigureService方法中注册SampleClient
services.AddHttpClient<ISampleClient, SampleClient>();
  1. 调用:
public class ValuesController : Controller
{
private readonly ISampleClient _sampleClient;
public ValuesController(ISampleClient sampleClient)
{
_sampleClient = sampleClient;
} [HttpGet]
public async Task<ActionResult> Get()
{
string result = await _sampleClient.GetData();
return Ok(result);
}
}

微软官网:在 ASP.NET Core 中使用 IHttpClientFactory 发出 HTTP 请求

.Net4.5及.Net Core2.1下的HttpClient使用详解的更多相关文章

  1. Mac下安装HBase及详解

    Mac下安装HBase及详解 1. 千篇一律的HBase简介 HBase是Hadoop的数据库, 而Hive数据库的管理工具, HBase具有分布式, 可扩展及面向列存储的特点(基于谷歌BigTabl ...

  2. ava下static关键字用法详解

    Java下static关键字用法详解 本文章介绍了java下static关键字的用法,大部分内容摘自原作者,在此学习并分享给大家. Static关键字可以修饰什么? 从以下测试可以看出, static ...

  3. Linux下tomcat的安装详解

    Linux下tomcat的安装详解 来源: ChinaUnix博客 日期: 2007.01.21 22:59 (共有0条评论) 我要评论 一,安装前的准备:1,Linux版本:我的是企业版.(至于红帽 ...

  4. Linux下的文件目录结构详解

    Linux下的文件目录结构详解 / Linux文件系统的上层根目录 /bin 存放用户可执行的程序 /boot 操作系统启动时所需要的文件 /dev 接口设备文件目录,例如:had表示硬盘 /etc ...

  5. Linux下find命令用法详解

    Linux下find命令用法详解   学神VIP烟火 学神IT教育:XueGod-IT   最负责任的线上直播教育平台   本文作者为VIP学员 烟火   第一部分:根据文件名查找   1.在当前目录 ...

  6. Spring Boot 2.x 快速入门(下)HelloWorld示例详解

    上篇 Spring Boot 2.x 快速入门(上)HelloWorld示例 进行了Sprint Boot的快速入门,以实际的示例代码来练手,总比光看书要强很多嘛,最好的就是边看.边写.边记.边展示. ...

  7. Django--filter()-字段查找(双下划线的使用详解)

    Django--filter()-字段查找(双下划线的使用详解) 在了解django中的字段查找的同时,让我们先熟悉一下比较符: 大于--gt-(greater than) 小于--lt-(less ...

  8. (转)windows 下安装配置 Nginx 详解

    windows 下安装配置 Nginx 详解 本文转自https://blog.csdn.net/kingscoming/article/details/79042874 nginx功能之一可以启动一 ...

  9. linux下sort命令使用详解---linux将文本文件内容加以排序命令

    转载自:http://www.cnblogs.com/hitwtx/archive/2011/12/03/2274592.html linux下sort命令使用详解---linux将文本文件内容加以排 ...

  10. linux下getsockopt和setsockopt详解及测试

    linux下getsockopt和setsockopt详解及测试 NAME 名字 getsockopt, setsockopt - get and set options on sockets 获取或 ...

随机推荐

  1. 自定义Naive UI的数据表格Data Table中按钮Button图标

    在Naive UI官网中详细介绍了[数据表格 Data Table](数据表格 Data Table - Naive UI)的使用方式 { title: "Action", key ...

  2. 胃食管反流之 SAP分析( in the Ohmega software)

    原文:https://note.youdao.com/s/GED6wise SAP analysis in the Ohmega software ohmega software 关于胃食管反流疾病 ...

  3. Android 13 - Media框架(29)- MediaCodec(四)

    关注公众号免费阅读全文,进入音视频开发技术分享群! 上一节我们了解了如何通过 onInputBufferAvailable 和 getInputBuffer 获取到 input buffer inde ...

  4. RabbitMQ系列(五) RabbitMQ的文件和目录位置

    概述 每个RabbitMQ节点使用一些文件和目录,用于加载配置.存储数据 / 元数据 / 日志文件等等.这些文件和目录的位置是可以自定义的. 本指南涵盖: 1)如何自定义RabbitMQ节点所使用的各 ...

  5. Pyomo基础学习笔记:建模组成要素的编写方法

    1.Pyomo 简介 pyomo文档[数学建模]优化模型建模语言 Pyomo 入门教程 - 知乎 (zhihu.com) Pyomo 是基于 Python 的开源软件包,主要功能是建立数学规划模型,包 ...

  6. 适用于linux的bilibiliB站直播间弹幕爬虫脚本

    适用于linux的bilibiliB站直播间弹幕爬虫脚本,命令行运行之,输入到命令行,部分内容参考自网络,代码底部可见原始代码出处 BUFF:然而,经测试,每次爬只能读取10条弹幕记录,这就使得在(s ...

  7. 将mnist训练的caffemodel生成动态链接库DLL

    在项目程序中经常看到动态链接库,非常好奇,想自己实现一下,于是乎尝试一波.就因为这种好奇,每天都被bug所困扰... 1. 训练caffemodel 在windows环境下搭建caffe无果,转投Ub ...

  8. 算法学习笔记(39): 2-SAT

    SAT 问题,也就是可满足性问题 Boolean Satisfiability Problem,是第一个被证明的 NPC 问题. 但是特殊的 2-SAT 我们可以通过图论的知识在线性复杂度内求解,构造 ...

  9. 推荐一款免费的终端工具-Windterm

    Windterm 提到SSH终端工具,大家一定会想到putty.xshell.MobaXterm这些产品.但是当我使用Windterm后,我彻底改变了我对之前使用SSH终端工具的认知,其强大的能力,彻 ...

  10. 修改 WIN10 WIN11 操作系统启动菜单名称

    修改 WIN10 WIN11 操作系统启动菜单名称 一块硬盘装双系统后,自动更新的启动菜单名称可能无法区分WIN10.WIN11,需要通过"卷2"."卷3"字样 ...