考虑到.NETHttpClient在设计时考虑到了重用,并且在短期实例中的目标是long livedmemory leaks have been reported.在为多个用户调用端点时,您希望使用不同的持有者令牌(或任何授权头)对给定端点进行REST式调用的准则是什么?

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

鉴于上述代码可以由web应用程序上的任意多个线程调用,很可能第一行中设置的头与调用资源时使用的头不同.

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


Lifecycle

虽然HttpClient确实间接实现了IDisposable

推荐答案

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

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

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

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

public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)

记录了here个.


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

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

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);
}

然后,可以像下面这样使用它们:

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

.net相关问答推荐

.NET restore/build在使用组织包的Github Action工作流中调用时获得401

[x.x.x,)在Packages.lock.json依赖项中是什么意思?

WinForm Task.Wait :为什么它会阻塞 UI?

竖线在 PropertyGroup .csproj 文件中的含义

是否有任何为 C# 编写的模糊搜索或字符串相似函数库?

ASP.NET MVC:隐藏字段值不会使用 HtmlHelper.Hidden 呈现

找不到 Microsoft.Office.Interop Visual Studio

IEnumerable Count() 和 Length 的区别

使用多个 MemoryCache 实例

处理序列没有元素异常

为什么 Interlocked.Exchange 不支持布尔类型?

如何将 NuGet 与 Visual C# Express 一起使用?

HashSet 是否保留插入顺序?

有没有办法从方法返回匿名类型?

形成两个列表并集的最简单方法

如何从 XDocument 获取 Xml 作为字符串?

覆盖 ASP.NET MVC 中的授权属性

使用语句与最终try

将日期时间转换为时间跨度

获取磁盘上文件的大小