【问题标题】:How do I set a cookie on HttpClient's HttpRequestMessage如何在 HttpClient HttpRequestMessage 中设置 cookie
【发布时间】:2012-09-11 16:01:28
【问题描述】:

我正在尝试使用 web api 的 HttpClient 向需要以标识帐户的 HTTP cookie 形式登录的端点发布帖子(这只是 #ifdef 的内容)发行版)。

如何将 cookie 添加到 HttpRequestMessage

【问题讨论】:

    标签: c# rest asp.net-mvc-4 asp.net-web-api


    【解决方案1】:

    以下是为请求设置自定义 cookie 值的方法:

    var baseAddress = new Uri("http://example.com");
    var cookieContainer = new CookieContainer();
    using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
    using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
    {
        var content = new FormUrlEncodedContent(new[]
        {
            new KeyValuePair<string, string>("foo", "bar"),
            new KeyValuePair<string, string>("baz", "bazinga"),
        });
        cookieContainer.Add(baseAddress, new Cookie("CookieName", "cookie_value"));
        var result = await client.PostAsync("/test", content);
        result.EnsureSuccessStatusCode();
    }
    

    【讨论】:

    • Kimi 是正确的,但您也不应该将 HttpClient 包装在 using 中。 aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
    • 注意:如果您只使用 1 个 HttpClient 实例来执行多个请求,则使用 CookieContainer 的 cookie 将被缓存。从另一个用户那里获取 cookie 对用户是危险的。
    • "HttpClient 旨在被实例化一次并在应用程序的整个生命周期中重复使用。特别是在服务器应用程序中,为每个请求创建一个新的 HttpClient 实例将耗尽重负载下可用的套接字数量..." 从这里:asp.net/web-api/overview/advanced/…
    • @SergeyT 那么当他需要对同一资源进行单独会话调用时该怎么办? :)
    • @RobertMcLaws 不在此处所示的用例中。然而,在 .NET GitHub 上的讨论中,我注意到问题不在于正在处理的 HttpClient,而在于 HttpClientHandler。如果您保留 HttpClientHandler 的静态实例并将其传递给 HttpClient 构造函数并将 disposeHandler 设置为 false,您可以创建和处置您喜欢的任意数量的 HttpClient 实例,因为它实际上是拥有资源的 HttpMessageHandler,而不是 HttpClient。
    【解决方案2】:

    accepted answer 在大多数情况下是正确的方法。但是,在某些情况下,您需要手动设置 cookie 标头。通常,如果您设置“Cookie”标头,它会被忽略,但这是因为 HttpClientHandler 默认使用其 CookieContainer 属性作为 cookie。如果你禁用它,那么通过将 UseCookies 设置为 false 你可以手动设置 cookie 标头,它们将出现在请求中,例如

    var baseAddress = new Uri("http://example.com");
    using (var handler = new HttpClientHandler { UseCookies = false })
    using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
    {
        var message = new HttpRequestMessage(HttpMethod.Get, "/test");
        message.Headers.Add("Cookie", "cookie1=value1; cookie2=value2");
        var result = await client.SendAsync(message);
        result.EnsureSuccessStatusCode();
    }
    

    【讨论】:

    • 我已经追了几天一个错误,其中使用 SendAsync 发送的请求没有发送 cookie 标头;这让我意识到,除非你在 Handler 中设置 UseCookies = false,否则它不仅会使用 CookieContainer,还会默默地忽略请求头中存储的任何 Cookie!非常感谢!
    • 这个答案对于任何试图使用 HttpClient 作为代理的人都非常有帮助!
    • 现在就试试...如果有效...你应该得到一个很好的加拿大式拥抱。
    • 注意:如果您只使用 1 个 HttpClient 实例来执行多个请求,则使用 CookieContainer 的 cookie 将被缓存。从另一个用户那里获取 cookie 对用户是危险的。
    • 当有人试图添加“Cookie”标题而不是默默地丢失它时,那个愚蠢的东西应该抛出异常。花了我一个小时的生命。感谢您的解决方案。
    【解决方案3】:

    在这个问题上花了几个小时后,上面的答案都没有帮助我,所以我找到了一个非常有用的工具。

    首先,我使用 Telerik 的 Fiddler 4 详细研究了我的 Web 请求

    其次,我发现了这个对 Fiddler 有用的插件:

    https://github.com/sunilpottumuttu/FiddlerGenerateHttpClientCode

    它只会为您生成 C# 代码。一个例子是:

            var uriBuilder = new UriBuilder("test.php", "test");
            var httpClient = new HttpClient();
    
    
            var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, uriBuilder.ToString());
    
    
    
            httpRequestMessage.Headers.Add("Host", "test.com");
            httpRequestMessage.Headers.Add("Connection", "keep-alive");
         //   httpRequestMessage.Headers.Add("Content-Length", "138");
            httpRequestMessage.Headers.Add("Pragma", "no-cache");
            httpRequestMessage.Headers.Add("Cache-Control", "no-cache");
            httpRequestMessage.Headers.Add("Origin", "test.com");
            httpRequestMessage.Headers.Add("Upgrade-Insecure-Requests", "1");
        //    httpRequestMessage.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
            httpRequestMessage.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36");
            httpRequestMessage.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
            httpRequestMessage.Headers.Add("Referer", "http://www.translationdirectory.com/");
            httpRequestMessage.Headers.Add("Accept-Encoding", "gzip, deflate");
            httpRequestMessage.Headers.Add("Accept-Language", "en-GB,en-US;q=0.9,en;q=0.8");
            httpRequestMessage.Headers.Add("Cookie", "__utmc=266643403; __utmz=266643403.1537352460.3.3.utmccn=(referral)|utmcsr=google.co.uk|utmcct=/|utmcmd=referral; __utma=266643403.817561753.1532012719.1537357162.1537361568.5; __utmb=266643403; __atuvc=0%7C34%2C0%7C35%2C0%7C36%2C0%7C37%2C48%7C38; __atuvs=5ba2469fbb02458f002");
    
    
            var httpResponseMessage = httpClient.SendAsync(httpRequestMessage).Result;
    
            var httpContent = httpResponseMessage.Content;
            string result = httpResponseMessage.Content.ReadAsStringAsync().Result;
    

    请注意,我必须注释掉两行,因为这个插件还不是很完美,但它仍然完成了工作。

    免责声明:无论如何,我与 Telerik 或插件的作者都没有关联或认可。

    【讨论】:

    • 这与as this one 的答案基本相同,唯一与cookie 有关的部分是最后添加的标题。请注意该答案中的所有警告
    【解决方案4】:

    对我来说,简单的解决方案可以在 HttpRequestMessage 对象中设置 cookie。

    protected async Task<HttpResponseMessage> SendRequest(HttpRequestMessage requestMessage, CancellationToken cancellationToken = default(CancellationToken))
    {
        requestMessage.Headers.Add("Cookie", $"<Cookie Name 1>=<Cookie Value 1>;<Cookie Name 2>=<Cookie Value 2>");
    
        return await _httpClient.SendAsync(requestMessage, cancellationToken).ConfigureAwait(false);
    }
    

    【讨论】:

    • 请注意,接受的答案比这多 ton 并处理更多的边缘条件。它可用于做诸如仅 http 或范围 cookie、多值 cookie 等之类的事情。评分第二高的答案提出了与此相同的方法,但有更多的上下文和解释
    • @GeorgeMauer 可能你是对的。他们俩都从“HttpClient(handler)”创建了httpClient。就我而言,我正在从 httpClientPool.GetOrCreateHttpClient() 创建 _httpClient
    • 但是您实际上并没有在回答中表明这一点,也没有解释差异或好处(这实际上也不是问题,但我并不担心)。我并不是要粗鲁,重要的是要清楚这个答案会对谁有帮助,其他人不会更好地帮助。
    • 我相信这个答案只有在HttpClientHandler 上设置UseCookies = false 才有效,这是@GregBeech 的answer 的精髓。
    【解决方案5】:

    我遇到了类似的问题,对于我的 AspNetCore 3.1 应用程序,这个问题的其他答案不起作用。我发现在我的Startup.cs 中配置一个命名的 HttpClient 并使用 Cookie 标头的标头传播效果很好。它还避免了有关正确处理您的处理程序和客户端的所有问题。请注意,如果请求 cookie 的传播不是您所需要的(抱歉,Op),您可以在配置客户端工厂时设置自己的 cookie。

    使用IServiceCollection 配置服务

    services.AddHttpClient("MyNamedClient").AddHeaderPropagation();
    services.AddHeaderPropagation(options =>
    {
        options.Headers.Add("Cookie");
    });
    

    IApplicationBuilder配置

    builder.UseHeaderPropagation();
    
    • IHttpClientFactory 注入您的控制器或中间件。
    • 创建您的客户using var client = clientFactory.CreateClient("MyNamedClient");

    【讨论】:

    • 是否会使用 services.AddHeaderPropagation(options, 为后续请求添加 http cookie?
    猜你喜欢
    • 1970-01-01
    • 2021-08-15
    • 1970-01-01
    • 2018-07-02
    • 1970-01-01
    • 1970-01-01
    • 2013-02-07
    相关资源
    最近更新 更多