静态 HttpClient 线程在 ASP.net HttpRequest 上是安全的



我们正在为 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());
}

}

您的团队是正确的,这远非线程安全。请考虑以下方案:

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

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

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

最新更新