译者:王亮
作者:Polly 团队
原文:http://t.cn/EhZ90oq
声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的(包括标题)。其中可能会去除一些不影响理解但本人实在不知道如何组织的句子

译者序:这是“Polly and HttpClientFactory”这篇Wiki文档翻译的下篇。你可以 点击这里查看上篇,和 点击这里查看中篇。本篇(下篇)主要讲几个Polly和HttpClientFactory在ASP.NET Core中结合使用的用例。如果你对ASP.NET Core 2.1新引入的HttpClient工厂还比较陌生,建议先阅读我的另一篇文章 .NET Core中正确使用 HttpClient的姿势,这有助于更好地理解本文。

—— 正文 ——

下面主要讲几个Polly和HttpClientFactory在ASP.NET Core中结合使用的用例。

用例:应用超时策略

HttpClient已经有了一个Timeout属性,但是在使用重试策略时该如何应用呢?Polly的超时策略又适用于什么地方?

  • HttpClient.Timeout属性设置的超时将被应用于HttpClient实例的所有调用,包括重试之间的所有尝试和等待。

  • 要在每次重试中使用超时,就要在Polly的超时策略之前配置重试策略。

在这种情况下,你可能希望重试策略在每次单个超时时重试。为此,需要让重试策略处理超时策略抛出的TimeoutRejectedException异常。

下面这个示例使用了上篇提到的Polly.Extensions.Http这个包,它可以很方便地为Http错误(比如HttpRequestException、Http 5XX和Http 408等)添加额外的处理。

using Polly.Extensions.Http;

var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.Or<TimeoutRejectedException>() // 若超时则抛出此异常
.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
}); // 为每个重试定义超时策略
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(10); serviceCollection.AddHttpClient("GitHub", client =>
{
client.BaseAddress = new Uri("https://api.github.com/");
client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
client.Timeout = TimeSpan.FromSeconds(60); // 默认超时时间
})
.AddPolicyHandler(retryPolicy)
// 将超时策略放在重试策略之内,每次重试会应用此超时策略
.AddPolicyHandler(timeoutPolicy);

用例:缓存策略

Polly 的缓存策略可以在通过IHttpClientFactory配置的委托处理程序中使用。Polly是通用的(不与Http请求绑定),因此在编写代码时,Polly缓存策略从Polly.Context中确定要使用的缓存键。可以通过HttpRequestMessage请求上的一个扩展方法来设置这个参数:

request.SetPolicyExecutionContext(new Polly.Context("CacheKeyToUseWithThisRequest"));

由于Polly缓存策略是在HttpResponseMessage级别的委托代理服务上进行缓存,因此还需要考虑下面的问题。

HttpResponseMessage级别的缓存是否合适?

如果你想重用HttpResponseMessage,那么在HttpResponseMessage级别上进行缓存可能非常合适。

但在某些情况下,比如调用WebService来获取一些序列化数据,然后反序列化到应用程序中的本地类型,HttpResponseMessage可能不是缓存的最佳粒度。

在这些情况下,HttpResponseMessage级别上的缓存意味着每次命中缓存都会重复读取数据流和反序列化,这在性能方面是不必要的。

在更高级别缓存可能更合适——例如,缓存流或反序列化到应用程序的本地类型的结果。

缓存HttpResponseMessage还要考虑以下三点:

  • HttpResponseMessage可以包含HttpContent,它只能向前读取流(只能读取一次)。这可能意味着,当CachePolicy第二次从缓存中检索它时,除非重新初始化流指针,否则无法重新读取流。
  • 考虑去个性化和时间戳。缓存的个人特有信息和时间戳可能不适合重新提供给后续的请求。
  • 注意只缓存状态码为200(OK)的响应。考虑使用Response.EnsureSuccessStatusCode()等方法确保只有成功的响应才能传递给缓存策略。或者你可以使用这里(http://t.cn/Ehnr78P)描述的自定义ITtlStrategy。

用例:在策略执行和调用之间交换信息

Polly策略的每次执行都会携带Polly.Context类的一个执行域实例(execution-scoped instance),该类的作用是提供上下文,并允许在执行前、执行中和执行后阶段之间交换信息(译注:类似于HttpContext)。

对于通过HttpClientFactory和Polly配置的HttpClient,可以在执行之前使用扩展方法HttpRequestMessage.SetPolicyExecutionContext(context)来设置被用于Http调用的上下文Polly.Context。该上下文具有字典语义,允许您传递任意数据。

var context = new Polly.Context();
context["MyCustomData"] = foo; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri);
request.SetPolicyExecutionContext(context); var response = await client.SendAsync(request, cancellationToken);

Polly将该上下文实例作为输入参数传递给策略上配置的任何委托钩子(例如onRetry)。例如下面这个已经预先配置了策略的HttpClient:

var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
},
onRetryAsync: async (outcome, timespan, retryCount, ctx) => {
/* Do something with ctx["MyCustomData"] */
// ...
});

委托钩子可以在执行期间设置其上下文信息:

var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
},
onRetryAsync: async (outcome, timespan, retryCount, ctx) => {
ctx["RetriesInvoked"] = retryCount;
// ...
});

这些信息可以在执行后从上下文中读取:

var response = await client.SendAsync(request, cancellationToken);

var context = response.RequestMessage?.GetPolicyExecutionContext(); // 如果还没有保存在局部变量中
if (context?.TryGetValue("RetriesInvoked", out int? retriesNeeded) ?? false)
{
// Do something with int? retriesNeeded
}

注意,只有在执行之前使用HttpRequestMessage.SetPolicyExecutionContext(context)设置了上下文时,HttpRequestMessage.GetPolicyExecutionContext()的获得的上下文才可用。

相关阅读:

.NET 开源项目 Polly 介绍

在 .NET Core 中结合 HttpClientFactory 使用 Polly(上篇)

在 .NET Core 中结合 HttpClientFactory 使用 Polly(中篇)

在 .NET Core 中结合 HttpClientFactory 使用 Polly(下篇)的更多相关文章

  1. 在 .NET Core 中结合 HttpClientFactory 使用 Polly(中篇)

    译者:王亮作者:Polly 团队原文:http://t.cn/EhZ90oq声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的(包括标题).其中可能会去除一些不影响理解但本人实在不知道如 ...

  2. 在 .NET Core 中结合 HttpClientFactory 使用 Polly(上篇)

    译者:王亮作者:Polly 团队原文:http://t.cn/EhZ90oq 译者序一:前两天写了一篇文章 .NET Core 开源项目 Polly 介绍,在写这篇文章查看 Polly 资料时,看到了 ...

  3. 在ASP.NET Core中用HttpClient(六)——ASP.NET Core中使用HttpClientFactory

    ​到目前为止,我们一直直接使用HttpClient.在每个服务中,我们都创建了一个HttpClient实例和所有必需的配置.这会导致了重复代码.在这篇文章中,我们将学习如何通过使用HttpClient ...

  4. 第十七节:.Net Core中新增HttpClientFactory的前世今生

    一. 背景 1.前世 提到HttpClient,在传统的.Net版本中简直臭名昭著,因为我们安装官方用法 using(var httpClient = new HttpClient()),当然可以Di ...

  5. 工厂参观记:.NET Core 中 HttpClientFactory 如何解决 HttpClient 臭名昭著的问题

    在 .NET Framework 与 .NET Core 中 HttpClient 有个臭名昭著的问题,HttpClient 实现了 IDispose 接口,但当你 Dispose 它时,它不会立即关 ...

  6. .net core 中使用httpclient,HttpClientFactory的问题

    Microsoft 在.Net Framework 4.5中引入了HttpClient,并且是在.NET服务器端代码中使用Web API的最常用方法.但它有一些严重的问题,如释放HttpClient对 ...

  7. HttpClient在.NET Core中的正确打开方式

    问题来源 长期以来,.NET开发者都通过下面的方式发送http请求: using (var httpClient = new HttpClient()) { var response = await ...

  8. .NetCore 2.1中的HttpClientFactory最佳实践

    .NET Core 2.1中的HttpClientFactory最佳实践 ASP.NET Core 2.1中出现一个新的HttpClientFactory功能, 它有助于解决开发人员在使用HttpCl ...

  9. Asp.Net Core中HttpClient的使用方式

    在.Net Core应用开发中,调用第三方接口也是常有的事情,HttpClient使用人数.使用频率算是最高的一种了,在.Net Core中,HttpClient的使用方式随着版本的升级也发生了一些变 ...

随机推荐

  1. [JavaScript] JavaScript事件注册,事件委托,冒泡,捕获,事件流

    面试题 event 事件 事件委托是什么? 如何阻止事件冒泡,阻止默认事件呢? Javascript 的事件流模型都有什么? 事件绑定和普通事件有什么区别? Event 对象 Event 对象,当事件 ...

  2. VS项目发布到本地IIS

    一.项目介绍 ①web项目,开发工具Visual Studio,语言C# ②本地IIS,手机上或其他用户在和本地在同一个局域网(并不绝对是指同一个WIFI)内访问,同时要把防火墙关掉 ③IIS全名In ...

  3. Eclipse Ctrl+Space 无法工作的问题

    Window->preference->Keys 然后找到content Assist,然后重新设置为自己想要的Short cut 就好了

  4. Linux常见命令(一)

    三.常见linux命令: 命令提示符的解释: (1).组成(默认):[root@localhost~]# (2)[root@localhost~] root:系统当前登录账户名称,超级管理员为root ...

  5. Js与jQuery的相互转换

    $()与jQuery() jQuery中$函数,根据传入参数的不同,进行不同的调用,实现不同的功能.返回的是jQuery对象 jQuery这个js库,除了$之外,还提供了另外一个函数:jQuery j ...

  6. loj#6073. 「2017 山东一轮集训 Day5」距离(费用流)

    题意 题目链接 Sol 我们可以把图行列拆开,同时对于行/列拆成很多个联通块,然后考虑每个点所在的行联通块/列联通块的贡献. 可以这样建边 从S向每个行联通块连联通块大小条边,每条边的容量为1,费用为 ...

  7. SAP 用户参数 ME_USE_GRID

    SAP 用户参数 ME_USE_GRID SAP的一些标准报表格式极其不友好,如果不做特殊参数设定,报表使用起来很不方便.我们可以通过设置user parameter的方式,改变一些报表的显示格式,让 ...

  8. [ SHELL编程 ] 字符串空格和文件空行删除

    1.删除字符串中空格 (1)删除行首空格 (2)删除行尾空格 (3)删除前.后空格,不删除中间空格 (4) 删除字符串中所有空格 echo " 123 567 " | sed 's ...

  9. <4>Python切片功能剖析

    引用文章:https://mp.weixin.qq.com/s/NZ371nKs_WXdYPCPiryocw 切片基础法则: (1)公式,禁止0. (2)i, n同号:从序列的第i位索引起,向右取n- ...

  10. 解决jest处理es模块

    解决jest处理es模块 问题场景 项目使用jest进行测试时, 当引入外部库是es模块时, jest无法处理导致报错. Test suite failed to run Jest encounter ...