6

答案显示如何将 cookie 添加到 HttpClient 请求。但是其中一条评论警告说CookieContainer缓存在 HttpClient 上。我的大部分 cookie 不应再次发送给其他用户。

我希望HttpClientFactory清除CookieContainer它的池中的 HttpClient 实例之类的东西。

如果我HttpClient通过电话得到我的,我得到的httpClientFactory.CreateClient是否有可能有一个以前CookieContainer的?

更新:

我的问题的答案是肯定的! CookieContainer适用于您希望在每次通话中发送相同的 cookie 时。

如果您需要在每次调用时发送不同的 cookie,有几种方法可以做到这一点。但最简单的是将它放在标题中。

因为客户端的每个请求HttpClientFactory都会创建一个新HttpClient的,所以您可以添加到客户端的标头中,而不必担心它会重用 cookie。

这样做的关键是设置UseCookies。它必须设置为 false,否则您添加到标头的 cookie 将被忽略。完成此操作后,您可以将 cookie 添加到“Cookies”键下的标题中,并将它们作为分号分隔的键值对输入(它们之间使用等号)。您的 cookie 在标题“Set-Cookies”中返回。

4

3 回答 3

5

HttpMessageHandler是被汇集的实例;不是HttpClient实例。默认情况下,处理程序的生命周期为 2 分钟,这意味着a可能会在多个sCookieContainer之间共享。HttpClient

官方文档中有一个部分,它解释了自动 cookie 处理和IHttpClientFactory不能很好地协同工作:

池化的HttpMessageHandler实例导致CookieContainer对象被共享。意外CookieContainer的对象共享通常会导致错误的代码。对于需要 cookie 的应用程序,请考虑:

  • 禁用自动 cookie 处理
  • 避免IHttpClientFactory

调用ConfigurePrimaryHttpMessageHandler以禁用自动 cookie 处理:

services.AddHttpClient("configured-disable-automatic-cookies")
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        return new SocketsHttpHandler()
        {
            UseCookies = false,
        };
    });
于 2020-12-10T09:25:34.357 回答
2

找到HttpClientFactory.

多年来,它已从一个仓库转移到另一个仓库:

  1. aspnet/HttpClientFactory
  2. dotnet/扩展
  3. dotnet/运行时

我们对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定义如下所示:

_activeHandlers = new ConcurrentDictionary<string, Lazy<ActiveHandlerTrackingEntry>>(StringComparer.Ordinal);
_entryFactory = (name) =>
{
    return new Lazy<ActiveHandlerTrackingEntry>(() =>
    {
        return CreateHandlerEntry(name);
    }, LazyThreadSafetyMode.ExecutionAndPublication);
};

如果您愿意,可以跳转到初始化新处理程序的内部CreateHandlerEntry方法,但我认为从主题角度来看它超出了范围。

因此,如您所见,当您获得一个已经存在的实例时,没有任何逻辑可以进行任何类型的清理。通过或者你可以注入一些代码,就像他们在测试期间所做的optionsMonitor那样。HttpClientActionsHttpMessageHandlerBuilderActions

Stephen Gordon 写了一篇关于 HttpClient 实例的创建和处置的文章,值得一读。

于 2020-12-10T08:46:02.880 回答
2

CookieContainer在我看来,紧密耦合的事实HttpClient是一个主要的设计缺陷,因为它不允许您(正确地)在模拟多个 cookie“会话”时使用后者的单个实例。正如所指出的那样,HttpClientFactory这并不能解决这个问题 - 您仍然坚持CookieContainer自己放弃和处理原始标头,或者拥有HttpClient比您真正需要的更多的实例。

我最近用 Flurl作为 3.0 中的一个主要新特性解决了这个问题。如果您不介意库依赖关系,这一切都HttpClient在幕后,但它替换CookieContainer为一个类似的概念 ( CookieJar),它支持相同的自动 cookie 处理,但使单客户端/多会话场景成为可能。

于 2020-12-11T19:56:28.520 回答