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


譯者:王亮
作者: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(中篇)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM