前言
上次,我們介紹了《在 ASP.NET Core 中使用 HTTP 標頭傳播》。
但是有時候,當服務間需要互相調用時,也需要將創建一些自定義標頭傳播到目標服務。
比如, ServiceA 已經進行了身份驗證,那么當它調用 ServiceB 時,不需要傳播 HTTP 標頭 Authorization
,可以自定義 x-user-id
標頭, 直接告訴 ServiceB 當前用戶 ID。
1. 使用 HttpRequestMessage
最簡單的方法,創建 HttpRequestMessage 實例直接添加標頭。
ServiceA 的實現代碼如下:
[HttpGet]
public?async?Task<string>?Get()
{var?userId?=?GetUserId();//從認證信息中獲取var?request?=?new?HttpRequestMessage(HttpMethod.Get,?"/ServiceB");if?(!string.IsNullOrWhiteSpace(userId)){request.Headers.Add("x-user-id",?userId);}var?client?=?_clientFactory.CreateClient("ServiceB-Client");var?response?=??await?client.SendAsync(request);return?await?response.Content.ReadAsStringAsync();
}
但是,這種解決方案存在一個問題:
如果有多個調用其他服務的方法,我們需要重復相同的邏輯;
2.使用 DelegatingHandler
在 ASP.NET Core 中,我們經常會使用 Middleware, 它使用管道模式,可以對服務收到的請求進行處理:
而 DelegatingHandler
提供了幾乎相同的概念,但卻是在 HttpClient 發出傳出請求時。
實現代碼如下:
public?class?UserIdDelegatingHandler?:?DelegatingHandler
{protected?override?async?Task<HttpResponseMessage>?SendAsync(HttpRequestMessage?request,?CancellationToken?cancellationToken){var?userId?=?GetUserId();//從認證信息中獲取if?(!string.IsNullOrWhiteSpace(userId)?&&?!request.Headers.Contains("x-user-id")){request.Headers.TryAddWithoutValidation(Headers.CorrelationId,?userId);}return?await?base.SendAsync(request,?cancellationToken);}
}
然后修改 Startup.cs,注冊 UserIdDelegatingHandler:
public?void?ConfigureServices(IServiceCollection?services)
{services.AddHttpClient("ServiceB-Client",?options?=>?options.BaseAddress?=?new?Uri("http://localhost:57516")).AddHttpMessageHandler<UserIdDelegatingHandler>()......
}
現在,我們可以從調用服務的代碼中刪除有關注冊自定義標頭的所有代碼:
[HttpGet]
public?async?Task<string>?Get()
{var?client?=?_clientFactory.CreateClient("ServiceB-Client");var?response?=??await?client.GetAsync("/ServiceB");return?await?response.Content.ReadAsStringAsync();
}
結論
如果我們想向 HttpClient 添加任何標頭,無需修改業務代碼,只需調用 .AddHttpMessageHandler
注冊新的 DelegatingHandler 即可。
添加微信號【MyIO666】,邀你加入技術交流