HttpClient单实例,使用不同的身份验证标头。
HttpClient单实例,使用不同的身份验证标头。
鉴于 .net HttpClient 是为了重用而设计的,并且旨在长时间存在,而且短时间实例存在内存泄漏的问题。当我们想要对给定的终端点进行不同用户的 Restful 调用时,有哪些指导方针呢?
考虑到上述代码可能会被 Web 应用程序的任意数量的线程调用,很容易发生在第一行设置的 header 与调用资源时使用的 header 不一致的情况。
在不使用锁并保持无状态的 Web 应用程序的前提下,推荐的方法是如何为单个终端点创建和处理 HttpClient(我目前的做法是为每个终端点创建一个单独的客户端)?
生命周期
尽管 HttpClient 间接实现了 IDisposable 接口,但推荐的用法不是在每个请求后都进行释放。HttpClient 对象的预期使用寿命是在您的应用程序需要进行 HTTP 请求的整个生命周期内存在。使一个对象存在于多个请求之间,可以在设置 DefaultRequestHeaders 方面提供方便,并且无需在每个请求中重新指定 CredentialCache 和 CookieContainer,这在使用 HttpWebRequest 时是必需的。
HttpClient单例实例不同身份验证标头的问题产生的原因是,如果默认请求标头被更改,会影响其他线程发送的请求。因此,需要使用特定于请求的标头,而不是将其设置为默认标头。解决方法是使用扩展方法将更新标头的代码与其他代码隔离开来。通过扩展方法,可以在发送请求之前操纵HttpRequestMessage的标头。下面是一个示例扩展方法,分别用于GET和POST方法:
public static TaskGetAsync(this HttpClient httpClient, string uri, Action preAction) { var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri); preAction(httpRequestMessage); return httpClient.SendAsync(httpRequestMessage); } public static Task PostAsJsonAsync (this HttpClient httpClient, string uri, T value, Action preAction) { var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, uri) { Content = new ObjectContent (value, new JsonMediaTypeFormatter(), (MediaTypeHeaderValue)null) }; preAction(httpRequestMessage); return httpClient.SendAsync(httpRequestMessage); }
可以通过以下方式使用这些扩展方法:
var response = await httpClient.GetAsync("token", x => x.Headers.Authorization = new AuthenticationHeaderValue("basic", clientSecret));
对于需要为单个请求设置代理、Cookie容器等特定需求的情况,推荐使用具有所需配置的命名或类型化客户端,并为其他请求使用未命名客户端。为了不使用任何IoC容器,可以参考Microsoft官方文档中关于如何在控制台应用程序中使用IHttpClientFactory的示例。