在 .NET Core 中结合 HttpClientFactory 使用 Polly(中篇)
译者:王亮
作者:Polly 团队
原文:http://t.cn/EhZ90oq
声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的(包括标题)。其中可能会去除一些不影响理解但本人实在不知道如何组织的句子
译者序:这是“Polly and HttpClientFactory”这篇Wiki文档翻译的中篇,你可以 点击这里查看上篇。接下来的两篇则是在这个基础上进行加强。本篇(中篇)主要讲如何在ASP.NET Core中通过HttpClientFactory配置Polly策略。如果你对ASP.NET Core 2.1新引入的HttpClient工厂还比较陌生,建议先阅读我的另一篇文章 .NET Core中正确使用 HttpClient的姿势,这有助于更好地理解本文。
—— 正文 ——
下面主要讲如何在ASP.NET Core中通过HttpClientFactory配置Polly策略。
使用 AddTransientHttpErrorPolicy
让我们先回到上篇的例子:
services.AddHttpClient("GitHub", client =>
{
client.BaseAddress = new Uri("https://api.github.com/");
client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
})
.AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
}));
这里用了一个新的AddTransientHttpErrorPolicy方法,它可以很方便地配置一个策略来处理下面这些典型的HTTP调用错误:
- 网络错误(HttpRequestException 异常)
- HTTP状态码 5XX(服务器错误)
- HTTP状态码 408(请求超时)
AddTransientHttpErrorPolicy方法添加了一个策略,这个策略默认预配置了上面HTTP错误的过滤器。在builder => builder子句中,你可以定义策略如何处理这些错误,还可以配置Polly提供的其它策略,比如重试(如上例所示)、断路或回退等。
在AddTransientHttpErrorPolicy中处理网络错误、HTTP 5XX和HTTP 408是一种便捷的方式,但这不是必需的。如果此方法内置的错误过滤器不适合您的需要(你需要仔细考虑一下),您可以扩展它,或者构建一个完全定制的Polly策略。
扩展 AddTransientHttpErrorPolicy
AddTransientHttpErrorPolicy方法也可以从Polly的一个扩展包Polly.Extensions.Http中得到,它在上面的基础上进行了扩展。例如下面配置的策略可以处理429状态码:
using Polly.Extensions.Http;
// ...
var policy = HttpPolicyExtensions
.HandleTransientHttpError() // HttpRequestException, 5XX and 408
.OrResult(response => (int)response.StatusCode == 429) // RetryAfter
.WaitAndRetryAsync(/* etc */);
使用典型Polly语法配置好的策略
Polly 还有另一个扩展方法是AddPolicyHandler,它的一个重载方法可以接收任意IAsyncPolicy参数,所以你可以用典型的Polly语法先定义好任意的一个策略(返回类型为IAsyncPolicy),然后再传给AddPolicyHandler扩展方法。
下面这个例子演示了用AddPolicyHandler来添加一个策略,其中我们编写了自己的错误处理策略:
var retryPolicy = Policy.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(response => MyCustomResponsePredicate(response))
.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
}));
services.AddHttpClient("GitHub", client =>
{
client.BaseAddress = new Uri("https://api.github.com/");
client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
})
.AddPolicyHandler(retryPolicy);
类似的,你还可以配置其它策略,比如超时策略:
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(10);
services.AddHttpClient(/* etc */)
.AddPolicyHandler(timeoutPolicy);
所有通过HttpClient的调用返回的都是一个HttpResponseMessage对象,因此配置的策略必须是IAsyncPolicy对象(译注:HTTP请求返回的是HttpResponseMessage对象,Polly定义的策略是一个IAsyncPolicy对象,所以AddPolicyHandler方法接收的参数是这两者的结合体IAsyncPolicy对象)。非泛型的IAsyncPolicy可以通过下面的方式转换成泛型的IAsyncPolicy:
var timeoutPolicy = Policy.TimeoutAsync(10);
services.AddHttpClient(/* etc */)
.AddPolicyHandler(timeoutPolicy.AsAsyncPolicy<HttpResponseMessage>());
应用多个策略
所有策略配置的方法也可以链式地配置多个策略,例如:
services.AddHttpClient(/* etc */)
.AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
}))
.AddTransientHttpErrorPolicy(builder => builder.CircuitBreakerAsync(
handledEventsAllowedBeforeBreaking: 3,
durationOfBreak: TimeSpan.FromSeconds(30)
));
多个策略被应用的顺序
当您配置多个策略时(如上例所示),策略应用于从外部(第一次配置)到内部(最后配置)的顺序依次调用。在上面的示例中,调用的顺序是这样的:
- 首先通过(外部)重试策略,该策略将依次:
- 通过(内部)断路策略的调用,该策略将依次:
- 进行底层HTTP调用。
这个示例之所以用此顺序的策略是因为当重试策略在两次尝试之间等待时,断路器可能在其中一个时间段(1、5或10秒)内改变状态(译注:上面示例中断路策略是出现3次异常就“休息”30分钟)。断路策略被配置在重试策略的内部,因此每执行一次重试就会执行其内部的断路策略。
上面的例子应用了两个策略(重试和断路),任意数量的策略都是可以的。一个常见的多个策略组合可能是这样的:重试、断路和超时(“下篇”会有例子)。
对于那些熟悉Polly的策略包的人来说,使用上面的方式配置多个策略完全等同于使用策略包,也适用于所有“策略包的使用建议”(链接:http://t.cn/EhJ4jfN)。
动态选择策略
AddPolicyHandler的重载方法允许你根据HTTP请求动态选择策略。
其中一个用例是对非等幂的操作应用不同的策略行为(译注:“等幂“指的是一个操作重复使用,始终都会得到同一个结果)。对于HTTP请求来说,POST操作通常不是幂等的(译注:比如注册),PUT操作应该是幂等的。所以对于给定的API可能不是一概而论的。比如,您可能想要定义一个策略,让它只重试GET请求,但不重试其他HTTP谓词,比如这个示例:
var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
});
var noOpPolicy = Policy.NoOpAsync().AsAsyncPolicy<HttpResponseMessage>();
services.AddHttpClient(/* etc */)
// 如果是GET请求,则使用重试策略,否则使用空策略
.AddPolicyHandler(request => request.Method == HttpMethod.Get ? retryPolicy : noOpPolicy);
上面的空策略会被应用于所有非GET的请求。空策略只是一种占坑模式,实际上不做任何事情。
从策略的注册池中选择策略
Polly还提供了策略注册池(请参阅:http://t.cn/Ehi1SQp ),它相当于策略的存储中心,被注册的策略可以让你在应用程序的多个位置重用。AddPolicyHandler的一个重载方法允许您从注册池中选择策略。
下面的示例使用IServiceCollection添加一个策略注册池服务,向注册池中添加一些策略,然后使用注册池中的不同策略定义两个调用逻辑。
var registry = services.AddPolicyRegistry();
registry.Add("defaultretrystrategy",
HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(/* etc */));
registry.Add("defaultcircuitbreaker",
HttpPolicyExtensions.HandleTransientHttpError().CircuitBreakerAsync(/* etc */));
services.AddHttpClient(/* etc */)
.AddPolicyHandlerFromRegistry("defaultretrystrategy");
services.AddHttpClient(/* etc */)
.AddPolicyHandlerFromRegistry("defaultretrystrategy")
.AddPolicyHandlerFromRegistry("defaultcircuitbreaker");
这个示例演示了从注册池中选择一个或多个策略应用在不同的HttpClient上,同一个策略被重复使用了两次。策略注册池的更复杂用例包括从外部动态更新注册池中的策略,以便在运行期间动态重新配置策略(请查阅 http://t.cn/Ehidgqy 了解更多)。
相关阅读:
在 .NET Core 中结合 HttpClientFactory 使用 Polly(中篇)的更多相关文章
- 在 .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(六)——ASP.NET Core中使用HttpClientFactory
到目前为止,我们一直直接使用HttpClient.在每个服务中,我们都创建了一个HttpClient实例和所有必需的配置.这会导致了重复代码.在这篇文章中,我们将学习如何通过使用HttpClient ...
- 第十七节:.Net Core中新增HttpClientFactory的前世今生
一. 背景 1.前世 提到HttpClient,在传统的.Net版本中简直臭名昭著,因为我们安装官方用法 using(var httpClient = new HttpClient()),当然可以Di ...
- 工厂参观记:.NET Core 中 HttpClientFactory 如何解决 HttpClient 臭名昭著的问题
在 .NET Framework 与 .NET Core 中 HttpClient 有个臭名昭著的问题,HttpClient 实现了 IDispose 接口,但当你 Dispose 它时,它不会立即关 ...
- .net core 中使用httpclient,HttpClientFactory的问题
Microsoft 在.Net Framework 4.5中引入了HttpClient,并且是在.NET服务器端代码中使用Web API的最常用方法.但它有一些严重的问题,如释放HttpClient对 ...
- HttpClient在.NET Core中的正确打开方式
问题来源 长期以来,.NET开发者都通过下面的方式发送http请求: using (var httpClient = new HttpClient()) { var response = await ...
- .NetCore 2.1中的HttpClientFactory最佳实践
.NET Core 2.1中的HttpClientFactory最佳实践 ASP.NET Core 2.1中出现一个新的HttpClientFactory功能, 它有助于解决开发人员在使用HttpCl ...
- Asp.Net Core中HttpClient的使用方式
在.Net Core应用开发中,调用第三方接口也是常有的事情,HttpClient使用人数.使用频率算是最高的一种了,在.Net Core中,HttpClient的使用方式随着版本的升级也发生了一些变 ...
随机推荐
- Docker快速搭建LNMP环境
一.使用Dockerfile制作镜像 前面的博客中已经介绍了如何基于容器制作镜像,此方法的原理是使用一个正在运行的容器,根据生产所需进行配置更改等操作后,使其满足生产环境,再将这个容器打包制作为镜像, ...
- 一统江湖的大前端(4)shell.js——穿上马甲我照样认识你
<一统江湖的大前端>系列是自己的前端学习笔记,旨在介绍javascript在非网页开发领域的应用案例和发现各类好玩的js库,不定期更新.如果你对前端的理解还是写写页面绑绑事件,那你真的是有 ...
- NLP入门(六)pyltp的介绍与使用
pyltp的简介 语言技术平台(LTP)经过哈工大社会计算与信息检索研究中心 11 年的持续研发和推广, 是国内外最具影响力的中文处理基础平台.它提供的功能包括中文分词.词性标注.命名实体识别.依 ...
- Collection集合。
Collection集合. java.util.Collection 接口. 没有索引 是所有单列集合的最顶层的接口,里面定义了所有单列集合共性的方法. 任意的单列集合都可以使用Collecion接口 ...
- Nunit的尝试
(ps:没有代码,只有理论) 单元测试 单元测试(Unit Test)的一个测试用例(Test Case)是一小段代码,用于测试一个小的程序功能的行为是否正常,保证开发的功能子项能正确完成并实现其基本 ...
- [MySQL] 测试where group by order by的索引问题
1. select * from test where a=xx group by b order by c 如何加索引 CREATE TABLE `index_test` ( `id` int ...
- 程序员50题(JS版本)(六)
程序26:给一个不多于5位的正整数.要求:一.求它是几位数,二.逆序打印出各位数字. var test=456; var arr=[]; arr[0]=test%10; arr[1]=parseInt ...
- #WEB安全基础 : HTML/CSS | 0x11 浅谈GET和POST
HTTP中的GET和POST请求方法 我上次提到了GET和POST,现在就让你来认识一下这些新朋友 请看图 POST和GET都是将用户输入到浏览器的数据发送给服务器,不过采用了两种不同的方式,POST ...
- SAP MM 事务代码MI31之思考
SAP MM 事务代码MI31之思考 1 - MI01之痛 多年SAP项目实施实践中,笔者之前对于SAP系统里盘点凭证创建(MI01)事务代码里的输入界面很是不爽: 第一,MI01输入了一行数据以后, ...
- 驰骋工作流引擎JFlow与activiti的对比 -总结
共同点: 1. 嵌入式的工作流引擎,降低集群复杂性. 2. 严格而灵活的流程版本控制 3. 支持多种数据库 4. 支持多种流程设计模式 5. 成熟度高的开源工作流,具有可靠的稳定性和性能. 区别: 1 ...