1 前言

Microsoft.Extensions.Http是一个设计非常优异的客户端工厂库,其提供了IHttpClientFactory用于创建HttpClientIHttpMessageHandlerFactory用于创建HttpMessageHandler

遗憾的是这个库目前仅非常试用于客户端,而不太适用于转发端。我们对客户端的定义是一个软件在某种业务下使用单账号请求远程服务器的客户端行为,此软件不再充当其它软件的服务端;对转发端的定义是一个软件运行时,帮它的的多个客户端请求远程服务器,同时一般对远程服务器的响应内容做一些包装或修改的软件。

有时哪怕是做客户端软件,当遇到下面需求时,HttpClient和Microsoft.Extensions.Http的者难以解决:

  1. 可以临时申请很多代理服务器
  2. 每个代理服务器能使用3分钟
  3. 使用这些代理服务器源源不断的请求到某站

如果我们使用Microsoft.Extensions.Http,则无法使用动态的代理服务器;如果我们使用动态创建和维护多个HttpClient实例,我们又回到造第二个Microsoft.Extensions.Http的需求。

2 HttpMessageHandlerFactory

HttpMessageHandlerFactory就是上面要造第二Microsoft.Extensions.Http的需求的产物,其它核心接口定义如下:

/// <summary>
/// Http消息处理者工厂
/// </summary>
public interface IHttpMessageHandlerFactory
{
/// <summary>
/// 创建用于请求的HttpMessageHandler
/// </summary>
/// <param name="name">别名</param>
/// <param name="proxyUri">支持携带UserInfo的代理地址</param>
/// <returns></returns>
HttpMessageHandler CreateHandler(string name, Uri? proxyUri);
}

当然HttpMessageHandlerFactory也提供了和Microsoft.Extensions.Http相似的Builder能力,在使用服务注册时没有额外的学习成本。

2.1 可选的ProxyUri参数

接口多了一个可选的Uri参数,有值的时候,代表要使用这个参数做代理。别小看这个Uri参数,它是可继承的类型,传入Uri的子类型还可以实现很多意想不到的骚操作。

2.2 支持创建HttpClient

IHttpMessageHandlerFactory提供创建HttpClient的扩展,用于做客户端模式,且支持传入与用户实例绑定的CookieContainer,然后Cookie就完全自动化处理。

/// <summary>
/// 创建Http客户端
/// </summary>
/// <param name="factory"></param>
/// <param name="name">别名</param>
/// <param name="proxyUri">支持携带UserInfo的代理地址</param>
/// <param name="cookieContainer">cookie容器</param>
/// <returns></returns>
public static HttpClient CreateClient(this IHttpMessageHandlerFactory factory, string name, Uri? proxyUri = null, CookieContainer? cookieContainer = null)
{
var httpHandler = factory.CreateHandler(name, proxyUri, cookieContainer);
return new HttpClient(httpHandler, disposeHandler: false);
}

2.3 支持创建HttpMessageInvoker

IHttpMessageHandlerFactory提供创建HttpMessageInvoker的扩展,用于转发端模式,且支持传入与用户实例绑定的CookieContainer,然后Cookie就完全自动化处理。

/// <summary>
/// 创建Http执行器
/// </summary>
/// <param name="factory"></param>
/// <param name="name">别名</param>
/// <param name="proxyUri">支持携带UserInfo的代理地址</param>
/// <param name="cookieContainer">cookie容器</param>
/// <returns></returns>
public static HttpMessageInvoker CreateInvoker(this IHttpMessageHandlerFactory factory, string name, Uri? proxyUri = null, CookieContainer? cookieContainer = null)
{
var httpHandler = factory.CreateHandler(name, proxyUri, cookieContainer);
return new HttpMessageInvoker(httpHandler, disposeHandler: false);
}

3 生态与扩展

如果说HttpMessageHandlerFactory只解决了Microsoft.Extensions.Http的Proxy痛点,但丢了Microsoft.Extensions.Http的生态又不能扩展的话,那无疑HttpMessageHandlerFactory是非常局限和失败的。

实际上Microsoft.Extensions.Http上层的很多组件,移植到HttpMessageHandlerFactory是非常简单的,简单说是DI注册扩展的IHttpClientBuilder改为IHttpMessageHandlerBuilder就行。

3.1 HttpMessageHandlerFactory.Polly

为HttpMessageHandlerFactory提供Polly策略扩展,使得IHttpMessageHandlerBuilder拥有与IHttpClientFactory完全一致的Polly能力。

3.1.1 AddPolicyHandler能力

var retryPolicy = Policy.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(response =>
{
return response.IsSuccessStatusCode == false;
}).WaitAndRetryAsync(3, t => TimeSpan.FromSeconds(3d)); services
.AddHttpMessageHandlerFactory("App")
.AddPolicyHandler(retryPolicy);

3.1.2 AddPolicyHandlerFromRegistry能力

var retryPolicy = Policy.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(response =>
{
return response.IsSuccessStatusCode == false;
}).WaitAndRetryAsync(3, t => TimeSpan.FromSeconds(3d)); var registry = services.AddPolicyRegistry();
registry.Add("registry1", retryPolicy); services
.AddHttpMessageHandlerFactory("App")
.AddPolicyHandlerFromRegistry("registry1");

3.1.3 AddTransientHttpErrorPolicy能力

当以下任意条件成立时,触发TransientHttpErrorPolicy

  • HttpRequestException的网络故障
  • 服务端响应5XX的状态码
  • 408的状态码(request timeout)
services
.AddHttpMessageHandlerFactory("App")
.AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[] {
TimeSpan.FromSeconds(1d),
TimeSpan.FromSeconds(5d),
TimeSpan.FromSeconds(10d)
}));

3.2 HttpMessageHandlerFactory.Connection

为HttpMessageHandlerFactory提供自定义连接的功能。

注意此扩展项目不是免费项目,有如下限制:

  • 不开放和提供源代码
  • nuget包的程序集在应用程序运行2分钟后适用期结束
  • 适用期结束后所有的http请求响应为423 Locked
  • 需要license文件授权方可完全使用

3.2.1 自定义域名解析

  • 当无代理连接时,连接到自定义解析得到的IP
  • 当使用http代理时,让代理服务器连接到自定义解析得到的IP
  • 当使用socks代理时,让代理服务器连接到自定义解析得到的IP
services
.AddHttpMessageHandlerFactory("App")
.AddHostResolver<CustomHostResolver>();
sealed class CustomHostResolver : HostResolver
{
public override ValueTask<HostPort> ResolveAsync(DnsEndPoint endpoint, CancellationToken cancellationToken)
{
if (endpoint.Host == "www.baidu.com")
{
return ValueTask.FromResult(new HostPort("14.119.104.189", endpoint.Port));
}
return ValueTask.FromResult(new HostPort(endpoint.Host, endpoint.Port));
}
}

3.2.2 自定义ssl的sni

Server Name Indication (SNI) 是 TLS 协议(以前称为 SSL 协议)的扩展,该协议在 HTTPS 中使用。它包含在 TLS/SSL 握手流程中,以确保客户端设备能够看到他们尝试访问的网站的正确 SSL 证书。该扩展使得可以在 TLS 握手期间指定网站的主机名或域名 ,而不是在握手之后打开 HTTP 连接时指定。

services
.AddHttpMessageHandlerFactory("App")
.AddSslSniProvider<CustomSslSniProvider>();
sealed class CustomSslSniProvider : SslSniProvider
{
public override ValueTask<string> GetSslSniAsync(string host, CancellationToken cancellationToken)
{
return ValueTask.FromResult(string.Empty);
} public override bool RemoteCertificateValidationCallback(string host, X509Certificate? cert, X509Chain? chain, SslPolicyErrors errors)
{
return true;
}
}

4 两个库的场景选择

无/固定代理 动态代理 客户端 转发端
Microsoft.Extensions.Http 适合 不适合 非常适合 功能弱
HttpMessageHandlerFactory 适合 适合 功能弱 非常适合

HttpMessageHandlerFactory的源代码在https://github.com/xljiulang/HttpMessageHandlerFactory,其功能单一代码量相对Microsoft.Extensions.Http要少一些,阅读其代码之后去理解Microsoft.Extensions.Http会更容易很多。

dotnet平台Http消息处理者工厂的更多相关文章

  1. 使用Fsharp 探索 Dotnet 平台

    Fsharp的交互开发环境使得我们在了解DotNet平台时能够快速的获得需要的反馈. 反馈在任何技艺的磨练过程中必不可少,我认为也是最重要的环节之一.在“一万小时天才理论”中,著名的髓鞘质就是在快速有 ...

  2. 怎么使用瓦特平台下面的“代码工厂”快速生成BS程序代码

    这里说一下怎么使用瓦特平台下面的“代码工厂”快速生成程序代码 使用平台:windows+"visual studio 2010"+"SqlServer2000+" ...

  3. ASP.NET MVC5+EF6+EasyUI 后台管理系统(72)-微信公众平台开发-消息处理

    系列目录 前言 Senparc.Weixin.MP SDK提供了MessageHandler消息处理类 在作者的Wiki中也详细说明了如何定义这个类,下面我们来演示,消息的回复,及效果 了解Messa ...

  4. Jenkins在Windows系统dotnet平台持续集成

            之前写过一篇文章是在CentOS上构建.net自动化编译环境, 今天这篇是针对于Windows平台的环境.        Jenkins是一个开源软件项目,旨在提供一个开放易用的软件平 ...

  5. dotNet平台模板列中的单选无效的解决方案

    最近在grid里添加一个单选列,最开始直接创建一个模板列,然后在模板列里放一个radiobutton.并指定其GroupName.这是radiabutton最常用的方法.但是在Grid里,这样却毫无效 ...

  6. .NET平台下开源框架

    一.AOP框架Encase 是C#编写开发的为.NET平台提供的AOP框架.Encase 独特的提供了把方面(aspects)部署到运行时代码,而其它AOP框架依赖配置文件的方式.这种部署方面(asp ...

  7. .NET微信公众号开发-4.0公众号消息处理

    一.前言 微信公众平台的消息处理还是比较完善的,有最基本的文本消息,到图文消息,到图片消息,语音消息,视频消息,音乐消息其基本原理都是一样的,只不过所post的xml数据有所差别,在处理消息之前,我们 ...

  8. [2018-11-27]2018年12月1日宁波dotnet社区线下活动

    离上次活动,转眼又过了一个月,幸得各路大神支持,于本周六(12月1日),宁波dotnet社区的线下分享活动又来啦! 活动嘉宾及主题 董斌辉 2015-2019年微软全球最有价值专家(.NET方向) 2 ...

  9. [2018-10-17]宁波dotnet社区(NBDNC)第一次问卷关于dotnet技术栈的小调查

    最近(2018年10月7日至10月17日),为配合确定下一次社区线下活动主题,做了一次宁波dotnet社区(NBDNC)的本地dotnet技术栈调研,设计了一份问卷,在此做一次记录. 导出的问卷统计结 ...

  10. 使用代码生成器“代码工厂”快速生成B/S程序代码

    开发目的: 自动生成C#.HTML.JS.Ajax 代码 .可以节省大量的时间来做业务逻辑的代码,那些重复的代码就不需要....了 环境支持: 硬件环境:window .VS2010+.支持SQLSe ...

随机推荐

  1. MySQL 高级查询截取分析

    慢日志分析流程如下:[1]观察(至少跑一天),看看生产慢 SQL 情况.[2]开启慢查询日志,设置阈值,比如对超过5秒的 SQL 语句进行抓取.[3]explain+慢 SQL 分析.[4]show ...

  2. java创建线程的方式有几种?

    java中创建线程的方式有多少种,这个问题也是众多纷纭,这个时候更应该参考官方文档(https://docs.oracle.com/javase/8/docs/api/java/lang/Thread ...

  3. 一个斜杠引发的CDN资源回源请求量飙升

    背景 一个安静的晚上,突然接到小伙伴电话线上CDN回源异常,具体表现为请求量飙升,且伴有少量请求404,其中回源请求量飙升已经持续两天但一直未被发现,直到最近404请求触发了告警后分析log才同时发现 ...

  4. 最新版本 Stable Diffusion 开源AI绘画工具之部署篇

    目录 AI绘画 本地环境要求 下载 Stable Diffusion 运行启动 AI绘画 关于 AI 绘画最近有多火,既然你有缘能看到这篇文章,那么相信也不需要我过多赘述了吧? 随着 AI 绘画技术的 ...

  5. react webpack自定义配置

    在react当中,webpack的配置是被隐藏了的,如果想要配置webpack,有两种方法: 一.暴露出webpack的配置文件(不推荐) 执行 npm run eject 二.使用craco添加配置 ...

  6. 系统评价——层次分析法AHP的R语言实现(四)

    对一个事物的评价往往会涉及多个因素或者多个指标,评价是在多个因素相互作用下的一个综合判断.多指标综合评价方法具有以下的特点:包含若干个指标,分别说明被评价对象的不同方面,评价方法最终要对被评价对象作出 ...

  7. 开发轻量级REST API样板 基于Node.js、MongoDB 通过Mongoose驱动

    ZY.Node.Mongodb https://gitee.com/Z568_568/node.mongodb.git https://github.com/ZHYI-source/ZY.Node.M ...

  8. 二进制安装Kubernetes(k8s) v1.24.3 IPv4/IPv6双栈

    二进制安装Kubernetes(k8s) v1.24.3 IPv4/IPv6双栈 Kubernetes 开源不易,帮忙点个star,谢谢了 介绍 kubernetes(k8s)二进制高可用安装部署,支 ...

  9. 【前端黑魔法】浏览器打开任意可执行exe文件方法

    思路:通过注册表注册自定义URL协议执行bat脚本,将文件路径作为参数传入 环境:win10 前置问题与条件 问题1:可以从浏览器直接打开可执行文件吗? 答:不能.其实可以通过 ActiveXObje ...

  10. [中间件]Fastjson [转载]

    1 Fastjson的安全漏洞 本段摘自: fastjson到底做错了什么?为什么会被频繁爆出漏洞? 前段时间,fastjson被爆出过多次存在漏洞,很多文章报道了这件事儿,并且给出了升级建议. 但是 ...