合并的 HttpClient 实例是否保留 CookieContainer?
Do pooled HttpClient instances keep the CookieContainer?
此 answer 展示了如何将 cookie 添加到 HttpClient 请求。但是其中一条评论警告说 CookieContainer
缓存在 HttpClient 上。我的大部分 cookie 不应为不同的用户再次发送。
我希望 HttpClientFactory
可以清除其池中 HttpClient 实例中添加的 CookieContainer
s 之类的东西。
如果我通过调用 httpClientFactory.CreateClient
得到我的 HttpClient
是否有可能我得到的那个上面有以前的 CookieContainer
?
更新:
我的问题的答案是肯定的! CookieContainer
适用于每次调用都发送相同 cookie 的情况。
如果您需要在每次调用时发送不同的 cookie,有几种方法可以做到这一点。但最简单的是把它放在header.
因为 HttpClientFactory
为客户端的每个请求创建一个新的 HttpClient
,您可以添加到客户端的 header,而不用担心它会重复使用 cookie。
这样做的关键是设置UseCookies
。它必须设置为 false,否则您添加到 header 的 cookie 将被忽略。执行此操作后,您可以将 cookie 添加到您的 header 键“Cookies”下,并将它们作为分号分隔的键值对(它们之间有等号)输入。您的 cookie 返回 header“Set-Cookies”。
找到 HttpClientFactory
的实现有点棘手。
这些年来,它已从一个存储库移至另一个存储库:
我们对DefaultHttpClientFactory感兴趣。
先来看CreateClient :
public HttpClient CreateClient(string name)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
HttpMessageHandler handler = CreateHandler(name);
var client = new HttpClient(handler, disposeHandler: false);
HttpClientFactoryOptions options = _optionsMonitor.Get(name);
for (int i = 0; i < options.HttpClientActions.Count; i++)
{
options.HttpClientActions[i](client);
}
return client;
}
如您所见,它调用 CreateHandler 方法来检索 HttpMessageHandler
:
public HttpMessageHandler CreateHandler(string name)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
ActiveHandlerTrackingEntry entry = _activeHandlers.GetOrAdd(name, _entryFactory).Value;
StartHandlerEntryTimer(entry);
return entry.Handler;
}
_activeHandlers
定义looks like this:
_activeHandlers = new ConcurrentDictionary<string, Lazy<ActiveHandlerTrackingEntry>>(StringComparer.Ordinal);
_entryFactory = (name) =>
{
return new Lazy<ActiveHandlerTrackingEntry>(() =>
{
return CreateHandlerEntry(name);
}, LazyThreadSafetyMode.ExecutionAndPublication);
};
如果您愿意,可以跳转到初始化新处理程序的内部 CreateHandlerEntry 方法,但我认为从主题的角度来看它超出了范围。
所以正如您所见,当您获得一个已经存在的实例时,没有任何逻辑可以进行任何类型的清理。通过 optionsMonitor
的 HttpClientActions
或 HttpMessageHandlerBuilderActions
你可以注入一些代码,比如 they did during testing.
Stephen Gordon has written an article 关于 HttpClient 实例的创建和处理值得一读。
HttpMessageHandler
个实例被合并;不是 HttpClient
个实例。默认情况下,handlers 的生命周期为 2 分钟,这意味着 非常 有可能 CookieContainer
将在多个 HttpClient
s.
有一个 section in the official docs,它解释了自动 cookie 处理和 IHttpClientFactory
不能很好地协同工作:
The pooled HttpMessageHandler
instances results in CookieContainer
objects being shared. Unanticipated CookieContainer
object sharing often results in incorrect code. For apps that require cookies, consider either:
- Disabling automatic cookie handling
- Avoiding
IHttpClientFactory
Call ConfigurePrimaryHttpMessageHandler to disable automatic cookie handling:
services.AddHttpClient("configured-disable-automatic-cookies")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new SocketsHttpHandler()
{
UseCookies = false,
};
});
CookieContainer
与 HttpClient
紧密耦合这一事实在我看来是一个主要的设计缺陷,因为它不允许您(正确地)使用后者的单个实例,同时模拟多个 cookie“会话”。正如所指出的,HttpClientFactory
并没有解决这个问题——你仍然坚持要么放弃 CookieContainer
并自己处理原始 headers,要么拥有比你更多的 HttpClient
个实例真的需要。
我最近 solved this problem with Flurl 作为 3.0 的主要新功能。如果您不介意库依赖性,它都是 HttpClient
在幕后,但它用类似的概念 (CookieJar
) 替换了 CookieContainer
,它支持相同的自动 cookie 处理,但使 single-client/multi-session 可能的情况。
此 answer 展示了如何将 cookie 添加到 HttpClient 请求。但是其中一条评论警告说 CookieContainer
缓存在 HttpClient 上。我的大部分 cookie 不应为不同的用户再次发送。
我希望 HttpClientFactory
可以清除其池中 HttpClient 实例中添加的 CookieContainer
s 之类的东西。
如果我通过调用 httpClientFactory.CreateClient
得到我的 HttpClient
是否有可能我得到的那个上面有以前的 CookieContainer
?
更新:
我的问题的答案是肯定的! CookieContainer
适用于每次调用都发送相同 cookie 的情况。
如果您需要在每次调用时发送不同的 cookie,有几种方法可以做到这一点。但最简单的是把它放在header.
因为 HttpClientFactory
为客户端的每个请求创建一个新的 HttpClient
,您可以添加到客户端的 header,而不用担心它会重复使用 cookie。
这样做的关键是设置UseCookies
。它必须设置为 false,否则您添加到 header 的 cookie 将被忽略。执行此操作后,您可以将 cookie 添加到您的 header 键“Cookies”下,并将它们作为分号分隔的键值对(它们之间有等号)输入。您的 cookie 返回 header“Set-Cookies”。
找到 HttpClientFactory
的实现有点棘手。
这些年来,它已从一个存储库移至另一个存储库:
我们对DefaultHttpClientFactory感兴趣。
先来看CreateClient :
public HttpClient CreateClient(string name)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
HttpMessageHandler handler = CreateHandler(name);
var client = new HttpClient(handler, disposeHandler: false);
HttpClientFactoryOptions options = _optionsMonitor.Get(name);
for (int i = 0; i < options.HttpClientActions.Count; i++)
{
options.HttpClientActions[i](client);
}
return client;
}
如您所见,它调用 CreateHandler 方法来检索 HttpMessageHandler
:
public HttpMessageHandler CreateHandler(string name)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
ActiveHandlerTrackingEntry entry = _activeHandlers.GetOrAdd(name, _entryFactory).Value;
StartHandlerEntryTimer(entry);
return entry.Handler;
}
_activeHandlers
定义looks like this:
_activeHandlers = new ConcurrentDictionary<string, Lazy<ActiveHandlerTrackingEntry>>(StringComparer.Ordinal);
_entryFactory = (name) =>
{
return new Lazy<ActiveHandlerTrackingEntry>(() =>
{
return CreateHandlerEntry(name);
}, LazyThreadSafetyMode.ExecutionAndPublication);
};
如果您愿意,可以跳转到初始化新处理程序的内部 CreateHandlerEntry 方法,但我认为从主题的角度来看它超出了范围。
所以正如您所见,当您获得一个已经存在的实例时,没有任何逻辑可以进行任何类型的清理。通过 optionsMonitor
的 HttpClientActions
或 HttpMessageHandlerBuilderActions
你可以注入一些代码,比如 they did during testing.
Stephen Gordon has written an article 关于 HttpClient 实例的创建和处理值得一读。
HttpMessageHandler
个实例被合并;不是 HttpClient
个实例。默认情况下,handlers 的生命周期为 2 分钟,这意味着 非常 有可能 CookieContainer
将在多个 HttpClient
s.
有一个 section in the official docs,它解释了自动 cookie 处理和 IHttpClientFactory
不能很好地协同工作:
The pooled
HttpMessageHandler
instances results inCookieContainer
objects being shared. UnanticipatedCookieContainer
object sharing often results in incorrect code. For apps that require cookies, consider either:
- Disabling automatic cookie handling
- Avoiding
IHttpClientFactory
Call ConfigurePrimaryHttpMessageHandler to disable automatic cookie handling:
services.AddHttpClient("configured-disable-automatic-cookies") .ConfigurePrimaryHttpMessageHandler(() => { return new SocketsHttpHandler() { UseCookies = false, }; });
CookieContainer
与 HttpClient
紧密耦合这一事实在我看来是一个主要的设计缺陷,因为它不允许您(正确地)使用后者的单个实例,同时模拟多个 cookie“会话”。正如所指出的,HttpClientFactory
并没有解决这个问题——你仍然坚持要么放弃 CookieContainer
并自己处理原始 headers,要么拥有比你更多的 HttpClient
个实例真的需要。
我最近 solved this problem with Flurl 作为 3.0 的主要新功能。如果您不介意库依赖性,它都是 HttpClient
在幕后,但它用类似的概念 (CookieJar
) 替换了 CookieContainer
,它支持相同的自动 cookie 处理,但使 single-client/multi-session 可能的情况。