C# 如何使用共享的 HttpClient 传递 cookie

C# How to pass on a cookie using a shared HttpClient

我有以下设置:

JS 客户端 -> Web Api -> Web Api

我需要一直向下发送身份验证cookie。我的问题是将它从一个网站 api 发送到另一个网站。由于与使用 FormsAuthentication 的旧系统集成,我必须传递身份验证 cookie。

出于性能原因,我在以下字典中共享了一个 HttpClient 列表(每个网站一个 api):

private static ConcurrentDictionary<ApiIdentifier, HttpClient> _clients = new ConcurrentDictionary<ApiIdentifier, HttpClient>();

所以给定一个标识符我可以获取相应的 HttpClient。

以下有效,但我很确定这是错误的代码:

HttpClient client = _clients[identifier];
var callerRequest = HttpContext.Current.Items["MS_HttpRequestMessage"] as HttpRequestMessage;
string authCookieValue = GetAuthCookieValue(callerRequest);

if (authCookieValue != null)
{
    client.DefaultRequestHeaders.Remove("Cookie");
    client.DefaultRequestHeaders.Add("Cookie", ".ASPXAUTH=" + authCookieValue);
}

HttpResponseMessage response = await client.PutAsJsonAsync(methodName, dataToSend);

// Handle response...

这里的错误在于 1) 在请求中操作 DefaultRequestHeaders 似乎是错误的,并且 2) 由于 HttpClient 是共享的,因此两个同时的请求可能会弄乱 cookie。

我已经搜索了一段时间但没有找到解决方案,因为大多数有匹配问题的实例都会为每个请求实例化 HttpClient,因此能够设置所需的 headers,我正在尝试避免。

有一次我收到了使用 HttpResponseMessage 工作的请求。或许这可以启发解决方案。

所以我的问题是:有没有一种方法可以使用 HttpClient 为单个请求设置 cookie,这对使用同一实例的其他客户端是安全的?

您可以使用 HttpRequestMessage 和 SendAsync() 而不是调用 PutAsJsonAsync():

Uri requestUri = ...;
HttpMethod method = HttpMethod.Get /*Put, Post, Delete, etc.*/;
var request = new HttpRequestMessage(method, requestUri);
request.Headers.TryAddWithoutValidation("Cookie", ".ASPXAUTH=" + authCookieValue);
request.Content = new StringContent(jsonDataToSend, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);

更新: 要确保您的 HTTP 客户端不存储响应中的任何 cookie,您需要这样做:

var httpClient = new HttpClient(new HttpClientHandler() { UseCookies = false; });

否则,您可能会因为使用一个客户端并共享其他 cookie 而出现意外行为。