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 而出现意外行为。
我有以下设置:
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 而出现意外行为。