具有不同身份验证标头的 HttpClient 单个实例 [英] HttpClient single instance with different authentication headers

查看:28
本文介绍了具有不同身份验证标头的 HttpClient 单个实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

鉴于 .net HttpClient 的设计考虑了重用,并且旨在成为 长期存在内存泄漏已被报告活的实例.在为多个用户调用端点时,您希望使用不同的承载令牌(或任何授权标头)对给定端点进行安静调用的指南有哪些?

private void CallEndpoint(string resourceId, string bearerToken) {httpClient.DefaultRequestHeaders.Authorization =新的 AuthenticationHeaderValue("bearer", bearerToken);var response = await httpClient.GetAsync($"resource/{resourceid}");}

鉴于上述代码可以被 Web 应用程序上的任意数量的线程调用,很容易在第一行中设置的标头与调用资源时使用的标头不同.

在不使用锁和维护无状态 Web 应用程序引起争用的情况下,为单个端点创建和处理 HttpClient 的推荐方法是什么(我目前的做法是为每个端点创建一个客户端)?


<块引用>

生命周期

虽然 HttpClient 确实间接实现了 IDisposable接口,HttpClient的推荐用法是不要dispose在每次请求之后.HttpClient 对象旨在作为只要您的应用程序需要发出 HTTP 请求.有对象存在于多个请求中,可以设置一个地方DefaultRequestHeaders 并防止您必须重新指定内容就像每个请求上的 CredentialCache 和 CookieContainer 一样需要使用 HttpWebRequest.

解决方案

如果您的标头通常是相同的,那么您可以设置 DefaultRequestHeaders.但是您不需要使用该属性来指定标题.正如您已经确定的那样,如果您要使用同一个客户端有多个线程,那将不起作用.对一个线程上的默认标头所做的更改会影响在其他线程上发送的请求.

尽管您可以在客户端上设置默认标头并将它们应用于每个请求,但标头实际上是请求的属性.因此,当标头特定于请求时,您只需将它们添加到请求中即可.

request.Headers.Authorization = new AuthenticationHeaderValue("bearer", bearerToken);

这意味着您不能使用不涉及创建 HttpRequest 的简化方法.你需要使用

public TaskSendAsync(HttpRequestMessage 请求)

记录在此处.><小时>

有些人发现使用扩展方法将更新标题的代码与方法的其余部分隔离开很有帮助.

通过扩展方法完成的 GET 和 POST 方法示例,允许您在发送之前操作请求标头和更多 HttpRequestMessage:

public static Task获取异步(这个HttpClient httpClient, string uri, Action preAction){var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri);preAction(httpRequestMessage);返回 httpClient.SendAsync(httpRequestMessage);}公共静态任务PostAsJsonAsync;(这个HttpClient httpClient,字符串uri,T值,ActionpreAction){var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, uri){内容 = 新对象内容(值, 新 JsonMediaTypeFormatter(), (MediaTypeHeaderValue)null)};preAction(httpRequestMessage);返回 httpClient.SendAsync(httpRequestMessage);}

这些可以像下面这样使用:

var response = await httpClient.GetAsync("token",x =>x.Headers.Authorization = new AuthenticationHeaderValue("basic", clientSecret));

Given that the .net HttpClient has been designed with reuse in mind and is intended to be long lived and memory leaks have been reported in short lived instances. What guide lines are there where you want to make restful calls to a given endpoint using different bearer tokens (or any authorization header) when calling the endpoint for multiple users?

private void CallEndpoint(string resourceId, string bearerToken) {
  httpClient.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("bearer", bearerToken);
  var response = await httpClient.GetAsync($"resource/{resourceid}");
}

Given the above code could be called by any number of threads on a web application it is easily possible that the header set in the first line is not the same one that is used when calling the resource.

Without causing contention using locks and maintaining a stateless web application what is the recommended approach to creating and disposing HttpClients for a single endpoint (My current practice is to create a single client per endpoint)?


Lifecycle

Although HttpClient does indirectly implement the IDisposable interface, the recommended usage of HttpClient is not to dispose of it after every request. The HttpClient object is intended to live for as long as your application needs to make HTTP requests. Having an object exist across multiple requests enables a place for setting DefaultRequestHeaders and prevents you from having to respecify things like CredentialCache and CookieContainer on every request, as was necessary with HttpWebRequest.

解决方案

If your headers are usually going to be the same then you can set the DefaultRequestHeaders. But you don't need to use that property to specify headers. As you've determined, that just wouldn't work if you're going to have multiple threads using the same client. Changes to the default headers made on one thread would impact requests sent on other threads.

Although you can set default headers on the client and apply them to each request, the headers are really properties of the request. So when the headers are specific to a request, you would just add them to the request.

request.Headers.Authorization = new AuthenticationHeaderValue("bearer", bearerToken);

That means you can't use the simplified methods that don't involve creating an HttpRequest. You'll need to use

public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)

documented here.


Some have found it helpful to use extension methods to isolate the code that updates the headers from the rest of a method.

Example of GET and POST methods done through an extension method that allow you to manipulate the request header and more of the HttpRequestMessage before it is sent:

public static Task<HttpResponseMessage> GetAsync
    (this HttpClient httpClient, string uri, Action<HttpRequestMessage> preAction)
{
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri);

    preAction(httpRequestMessage);

    return httpClient.SendAsync(httpRequestMessage);
}

public static Task<HttpResponseMessage> PostAsJsonAsync<T>
    (this HttpClient httpClient, string uri, T value, Action<HttpRequestMessage> preAction)
{
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, uri)
    {
        Content = new ObjectContent<T>
            (value, new JsonMediaTypeFormatter(), (MediaTypeHeaderValue)null)
    };
    preAction(httpRequestMessage);

    return httpClient.SendAsync(httpRequestMessage);
}

These could then be used like the following:

var response = await httpClient.GetAsync("token",
    x => x.Headers.Authorization = new AuthenticationHeaderValue("basic", clientSecret));

这篇关于具有不同身份验证标头的 HttpClient 单个实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆