【问题标题】:Static HttpClient thread safe on ASP.net HttpRequestASP.net HttpRequest 上的静态 HttpClient 线程安全
【发布时间】:2015-06-28 00:49:57
【问题描述】:

我们正在为 HttpClient 创建一个包装器。因为我们将遵循https://github.com/mspnp/performance-optimization 的性能优化指导。我们希望避免反模式 - 该文档中提到的不正确实例化。我将此指南推荐给我的团队以使用静态 HttpClient。我得到的反馈是关于线程安全的。每个请求都有一个包含用户声明的标头。由于我有一个静态 HttpClient,它会是线程安全的吗?如果我们有多个请求同时访问代码(例如 GET),设置标头会是竞争条件吗?我们有如下实现。

public class HttpClientHelper{
private static readonly HttpClient _HttpClient;
static HttpClientHelper() {
        HttpClient = new HttpClient();
        HttpClient.Timeout = TimeSpan.FromMinutes(SOME_CONFIG_VALUE);
}

public async Task<HttpResponseMessage> CallHttpClientPostAsync(string requestUri, HttpContent requestBody)
{
    AddHttpRequestHeader(httpClient);
    var response = await httpClient.PostAsync(requestUri, requestBody); //Potential thread synchronization issue???
    return response;
}

public HttpResponseMessage CallHttpClientGet(string requestUri)
{
    AddHttpRequestHeader(httpClient);
    var response = httpClient.GetAsync(requestUri).Result; //Potential thread synchronization issue???
    return response;
}

private void AddHttpRequestHeader(HttpClient client)
{
    string HeaderName = "CorrelationId";
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(Properties.Settings.Default.HttpClientAuthHeaderScheme, GetTokenFromClaims()); //Race condition???
    if (client.DefaultRequestHeaders.Contains(HeaderName))
        client.DefaultRequestHeaders.Remove(HeaderName);
    client.DefaultRequestHeaders.Add(HeaderName, Trace.CorrelationManager.ActivityId.ToString());
}

}

【问题讨论】:

  • CallHttpClientGet 不是异步的任何原因?通过调用.Result,您正在阻塞线程并引发潜在的死锁。

标签: asp.net thread-safety httprequest static-libraries dotnet-httpclient


【解决方案1】:

您的团队是正确的,这远非线程安全。考虑这种情况:

  • 线程 A 将 CorrelationId 标头设置为“foo”。
  • 线程 B 将 CorrelationId 标头设置为“bar”。
  • 线程 A 发送请求,其中包含线程 B 的 CorrelationId。

更好的方法是让您的 CallXXX 方法创建新的 HttpRequestMessage 对象,并在这些对象上设置标题,然后使用 HttpClient.SendAsync 进行调用。

还请记住,仅当您对同一主机进行多次调用时,重复使用 HttpClient 实例才有用。

【讨论】:

  • “请记住,仅当您对同一主机进行多次调用时,重用 HttpClient 实例才有用” - 您对此有参考吗?
  • @OhadSchneider 它基于Daryl Miller's advice 为“您连接到的每个不同的API”使用一个实例。原因是性能优势(不必打开新连接等)仅与每个主机相关,某些 HttpClient 属性(如 DefatultHeaders)也是如此。然而,现在著名的socket problem 可能会稍微改变我的建议。 Windows 可以在 TIME_WAIT 中回收套接字以用于不同的主机吗?我不知道。我在那篇文章上发布了这个问题。
猜你喜欢
  • 2011-01-22
  • 2014-09-16
  • 2010-10-16
  • 2012-09-22
  • 2015-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多