EDITORIAL
ビューのソースポイントを経由して、前の2回の記事では、我々はプロジェクトで使用する場合、必ず以下の質問が伴うだろう内部実装HttpClientFactoryを理解します:
- HttpClientをアウト処理と再試行メカニズム
- ヒューズモード達成のHttpClient
- HttpClientをロギングと追跡チェーン
次は角度を使用して上記の問題点についての説明を行います。
細部
次のコードの参照MSDN、コードは、インタフェースに表示されているので、実際のGitHub、Iはインタフェースのテストを書くことが出てくる道を介して転送することができます。
HttpClientをアウト処理と再試行メカニズム
これに先立ち、私たちは、このライブラリポリーを見る必要があり、ポリーは、(回路)の開発者が円滑かつスレッドセーフな方法でリトライ(再試行)、回路ブレーカを実行することを可能にする柔軟かつ瞬時.NETのエラー処理ライブラリに基づいていますタイムアウト(タイムアウト)、隔壁分離(隔壁分離)とバックポリシー(フォールバック)。
次のコードは、.NETでコア3.0でタイムアウトメカニズムを使用する方法について説明します。
1: Policy.TimeoutAsync <HttpResponseMessage>(TimeSpan.FromSeconds(10))
だからの対応のHttpClientインスタンスに登録する方法を、多くの方法があります。
- AddPolicyHandlerを登録することにより、
1: services.AddHttpClient("githubの"、C =>
2: {
3: c.BaseAddress = 新しいウリ("https://api.github.com/");
4:
5: c.DefaultRequestHeaders.Add("同意する"、"アプリケーション/ vnd.github.v3 + JSONを")。
6: c.DefaultRequestHeaders.Add("ユーザエージェント"、"HttpClientFactory-試料")。
7: 。})AddPolicyHandler(Policy.TimeoutAsync <HttpResponseMessage>(TimeSpan.FromSeconds(10)))。
- 登録届出書ポリシーオブジェクトとオブジェクトは、それタイムアウトポリシーに追加しました
1: VARレジストリ= services.AddPolicyRegistry()。
2: VARタイムアウト= Policy.TimeoutAsync <HttpResponseMessage>(TimeSpan.FromSeconds(10))。
3: registry.Add("通常の"、タイムアウト);
呼ばれます
1: services.AddHttpClient("githubの"、C =>
2: {
3: c.BaseAddress = 新しいウリ("https://api.github.com/");
4:
5: c.DefaultRequestHeaders.Add("同意する"、"アプリケーション/ vnd.github.v3 + JSONを")。//のGitHub APIのバージョン
6: c.DefaultRequestHeaders.Add("ユーザエージェント"、"HttpClientFactory-試料")。// GitHubのは、ユーザーエージェントが必要です
7: 。})AddPolicyHandlerFromRegistry("通常")
ポリーはまた、再試行するのは非常に簡単です
1: VAR policyRegistry = services.AddPolicyRegistry()。
2:
3: policyRegistry.Add( "MyHttpRetry"、HttpPolicyExtensions.HandleTransientHttpError()WaitAndRetryAsync(。
3
、retryAttempt => TimeSpan.FromSeconds(Math.Pow(2、retryAttempt)
)));
ここでリトライ設定すると、最初の呼び出しが失敗した後、各要求の時間間隔が指数関数的に遅延された再試行を継続するために、3つのチャンスがあるだろうということです。
DelegatingHandlerをポリーが実装リトライ機能を使用するだけでなく、使用することができることに加えて、DelegatingHandlerは、本質的にHttpMessageHandler「双方向導管」とみなすことができる順序のセットの組み合わせである「応答を返信する、プロセスの要求」のために、HttpMessageHandlerから継承しました。
ここでの主なショーが実際に使用さDelegatingHandlerを使用し、ポリーは、もう一度試して使用することをお勧めします。
1: プライベート クラス RetryHandler:DelegatingHandler
2: {
3: 公共 int型 RetryCountの{取得します。セット; } = 5。
4:
5: 保護 オーバーライドタスク<HttpResponseMessage> SendAsync(HttpRequestMessage要求、CancellationToken cancellationToken)非同期
6: {
7: のための(VAR i = 0; I <RetryCountの、iは++)
8: {
9: 試します
10: {
11: リターン待つ基地 .SendAsync(リクエスト、cancellationToken)を、
12: }
13: キャッチ(HttpRequestException)は、(i == RetryCountの- 1)
14: {
15: 投げます。
16: }
17: キャッチ(HttpRequestException)
18: {
19: // 50ミリ秒後に再試行
20: Task.Delay(TimeSpan.FromMilliseconds(50))を待ちます。
21: }
22: }
23: }
24: }
次のようにサインアップ:
1: services.AddHttpClient("githubの"、C =>
2: {
3: c.BaseAddress = new Uri("https://api.github.com/");
4:
5: c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json"); // GitHub API versioning
6: c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample"); // GitHub requires a user-agent
7: })
8: .AddHttpMessageHandler(() => new RetryHandler());
HttpClient熔断器模式的实现
如果非常了解Polly库的使用,那么熔断器模式的实现也会非常简单,
1: var policyRegistry = services.AddPolicyRegistry();
2:
3: policyRegistry.Add("MyCircuitBreaker",HttpPolicyExtensions.HandleTransientHttpError().CircuitBreakerAsync(handledEventsAllowedBeforeBreaking: 10,durationOfBreak: TimeSpan.FromSeconds(30)));
这里的熔断器设置规则是在连续10次请求失败后,会暂停30秒。这个地方可以写个扩展方法注册到IServiceCollection中。
HttpClient日志记录与追踪链
日志记录这块与追踪链,我们一般会通过request.Header实现,而在微服务中,十分关注相关调用方的信息及其获取,一般的做法是通过增加请求Id的方式来确定请求及其相关日志信息。
实现思路是增加一个DelegatingHandler实例,用以记录相关的日志以及请求链路
1: public class TraceEntryHandler : DelegatingHandler
2: {
3: private TraceEntry TraceEntry { get; set; }
4:
5: public TraceEntryHandler(TraceEntry traceEntry)
6: {
7: this.TraceEntry = traceEntry;
8: }
9:
10: protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
11: {
12: request.Headers.TryAddWithoutValidation("X-TRACE-CID", this.TraceEntry.ClientId);
13: request.Headers.TryAddWithoutValidation("X-TRACE-RID", this.TraceEntry.RequestId);
14: request.Headers.TryAddWithoutValidation("X-TRACE-SID", this.TraceEntry.SessionId);
15: if (this.TraceEntry.SourceIP.IsNullOrEmpty())
16: {
17: request.Headers.TryAddWithoutValidation("X-TRACE-IP", this.TraceEntry.SourceIP);
18: }
19:
20: if (this.TraceEntry.SourceUserAgent.IsNullOrEmpty())
21: {
22: request.Headers.TryAddWithoutValidation("X-TRACE-UA", this.TraceEntry.SourceUserAgent);
23: }
24:
25: if (this.TraceEntry.UserId.IsNullOrEmpty())
26: {
27: request.Headers.TryAddWithoutValidation("X-TRACE-UID", this.TraceEntry.UserId);
28: }
29:
30: return base.SendAsync(request, cancellationToken);
31: }
32: }
我在查找相关资料的时候,发现有个老外使用CorrelationId组件实现,作为一种实现方式,我决定要展示一下,供大家选择:
1: public class CorrelationIdDelegatingHandler : DelegatingHandler
2: {
3: private readonly ICorrelationContextAccessor correlationContextAccessor;
4: private readonly IOptions<CorrelationIdOptions> options;
5:
6: public CorrelationIdDelegatingHandler(
7: ICorrelationContextAccessor correlationContextAccessor,
8: IOptions<CorrelationIdOptions> options)
9: {
10: this.correlationContextAccessor = correlationContextAccessor;
11: this.options = options;
12: }
13:
14: protected override Task<HttpResponseMessage> SendAsync(
15: HttpRequestMessage request,
16: CancellationToken cancellationToken)
17: {
18: if (!request.Headers.Contains(this.options.Value.Header))
19: {
20: request.Headers.Add(this.options.Value.Header, correlationContextAccessor.CorrelationContext.CorrelationId);
21: }
22:
23: // Else the header has already been added due to a retry.
24:
25: return base.SendAsync(request, cancellationToken);
26: }
27: }
参考链接:
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/http-requests?view=aspnetcore-3.0
https://rehansaeed.com/optimally-configuring-asp-net-core-httpclientfactory/