【问题标题】:How do I get cookies from HttpClientHandler.CookieContainer while using Web API self-hosting?如何在使用 Web API 自托管时从 HttpClientHandler.CookieContainer 获取 cookie?
【发布时间】:2014-05-22 22:49:59
【问题描述】:

我正在尝试为返回 cookie 的 Web API 方法编写集成测试。基于这个问题,我相信我需要设置一个HttpClientHandler的CookieContainer。

HttpClient Not Saving Cookies

然后,基于这个问题,我认为我需要将此 HttpClientHandler 设置为我的 HttpServer 实例的 InnerHandler 以便我可以链接处理程序。

How to perform in-memory test of HttpClientHandler

问题是我仍然发现 CookieContainer 是空的。我有一个断言,它验证响应中是否有一个标头,其中包含我期望的 cookie。这是我的代码:

        // Set up in-memory hosting of Web API
        var config = new HttpConfiguration();
        WebApiConfig.Register(config);

        var cookieJar = new CookieContainer();
        var httpClientHandler = new HttpClientHandler
        {
            CookieContainer = cookieJar,
            UseCookies = true                
        };
        var httpServer = new HttpServer(config)
        {
            InnerHandler = httpClientHandler
        };

        const string loginUrl = "http://localhost/api/authentication/login";
        var uri = new Uri(loginUrl);

        var client = new HttpClient(httpServer) { BaseAddress = uri };

        var response =
            client.PostAsJsonAsync(uri,
                new LoginMessage {Email = UserEmail, Password = Password},
                CancellationToken.None).Result;
        response.EnsureSuccessStatusCode();

        var data = response.Content.ReadAsAsync<LoginResponse>().Result;
        Assert.IsTrue(response.Headers.Contains("Set-Cookie"));
        Assert.AreNotEqual(0, httpClientHandler.CookieContainer.Count);

最后一个关于 CookieContainer 中项目数的断言失败。我也尝试调用httpClientHandler.CookieContainer.GetCookies(uri),但生成的 cookie 集合仍然包含零个元素。

我也尝试过显式链接我的客户端处理程序,但在行为上没有发现任何差异。

        var cookieJar = new CookieContainer();
        var httpClientHandler = new HttpClientHandler
        {
            CookieContainer = cookieJar,
            UseCookies = true
        };
        var httpServer = new HttpServer(config);

        var client = HttpClientFactory.Create(httpClientHandler, httpServer);

谁能告诉我在尝试检索这些 cookie 时我做错了什么?我在响应标头中看到的 cookie 如下所示:

Temp=E4C4947BAB708D089C636B4A5BDA094A10C8B1D66347EBD96629CB9BDB589822198A09BCBBE22C13D07AFC4D4C3C91E78C08BECFC9CC03BEE881858A1B4752EDC1BB1E604B819FBAFE34776B6F46B78ADCD2421F8125A395784981BFF22CEBE19DB228158E85B5786279E55D4114B72E50098B2374C23A43B7C89EBA30F771C54E1D98A6B1CD315D1FB8623E8E97E41FE4279479B49D0A948E2752CA09BD17FF7B52764E96EA43DB9E98D7CEBD8A73C9547A696C170CFC9B6F75CA23B881ED9675C2344A2A16BEF2DFD70DBA723FB62578E7779ECADCF11347B22199DAC8FA6A; expires=Thu, 22 May 2014 01:37:36 GMT; path=/

【问题讨论】:

  • 如果您查看您链接到的问题的已接受答案,您会发现要链接处理程序,您需要将 HttpServer 设置为内部处理程序。 HttpClientHandler 不是委托处理程序,因此无法链接它。我认为您只需要检查标题而不是尝试使用 CookieJar。
  • @DarrelMiller 感谢您澄清这一点。我不清楚哪个必须是内部处理程序,但我确实注意到 HttpClientHandler 不是委托处理程序。是否有一个可以处理 cookie 的委托处理程序的实现,或者你能指出我可以帮助我实现一个的资源吗?

标签: c# cookies asp.net-web-api dotnet-httpclient self-hosting


【解决方案1】:

根据我从 Darrel Miller 收到的关于原始问题的评论,看来处理这个问题的唯一方法是如果我们有一个使用 HttpServer 作为内部处理程序的委托处理程序。

我最终构建了自己的 CookieDelegateHandler,如下所示:

    public class CookieDelegateHandler : DelegatingHandler
    {
        public CookieContainer CookieContainer { get; set; }
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            return
                base.SendAsync(request, cancellationToken).ContinueWith(responseToCompleteTask
                    =>
                {
                    var result = responseToCompleteTask.Result;
                    var cookieHeaders = result.Headers.Where(pair => pair.Key == "Set-Cookie");
                    foreach (var value in cookieHeaders.SelectMany(header => header.Value))
                    {
                        CookieContainer.SetCookies(request.RequestUri, value);
                    }
                    return result;
                }, TaskContinuationOptions.OnlyOnRanToCompletion);
        }
    }

通过这个实现,我可以像这样实例化 HttpClient:

    var client = new HttpClient(new CookieDelegateHandler
    {
        CookieContainer = new CookieContainer(),
        InnerHandler = new HttpServer(config)
    });

执行委托处理程序的延续,并将 cookie 添加到 CookieContainer。

我欢迎任何其他关于如何在没有此自定义委托处理程序的情况下解决此问题的想法,或者关于我的解决方案中是否存在问题的 cmets。

【讨论】:

  • 将这种类型的功能作为单独的委派处理程序是长期的最佳选择。当我们开始迁移到 HTTP/2 时,我们将无法再使用 HttpClientHandler 并且需要重新实现的东西越少越好。重定向也是如此。 SO上有一个问题,我实现了自己的重定向处理程序。还有解压、缓存。
猜你喜欢
  • 1970-01-01
  • 2019-02-24
  • 1970-01-01
  • 1970-01-01
  • 2014-02-21
  • 1970-01-01
  • 2013-11-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多