如何在HttpClient的HttpRequestMessage上设置cookie

Geo*_*uer 218 c# rest asp.net-mvc-4 asp.net-web-api

我正在尝试使用web api HttpClient对端点进行发布,该端点需要以标识帐户的HTTP cookie的形式登录(这只是#ifdef发布版本之外的内容).

如何添加cookie HttpRequestMessage

Dar*_*rov 330

以下是为请求设置自定义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 = client.PostAsync("/test", content).Result;
    result.EnsureSuccessStatusCode();
}
Run Code Online (Sandbox Code Playgroud)

  • "HttpClient旨在实例化一次,并在应用程序的整个生命周期中重复使用.特别是在服务器应用程序中,为每个请求创建一个新的HttpClient实例将耗尽重负载下可用的套接字数量......"从这里:https ://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client (27认同)
  • Kimi是正确的,但你也不应该将你的HttpClient包装在一个使用中.http://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/ (16认同)
  • 注意:如果您只使用1个HttpClient实例来执行多个请求,则使用CookieContainer的cookie将被缓存.用户从另一个用户获取cookie是危险的. (7认同)
  • @SergeyT那么当他需要对同一资源进行单独的会话调用时,他会怎么做?:) (4认同)
  • @RobertMcLaws 不在此处显示的用例中。但是,在 .NET GitHub 上的讨论中,我注意到问题不在于正在处理的 HttpClient,而在于 HttpClientHandler。如果您保留 HttpClientHandler 的静态实例并将其传递给 HttpClient 构造函数并将 `disposeHandler` 设置为 false,则您可以创建和处置任意数量的 HttpClient 实例,因为它实际上是拥有资源的 HttpMessageHandler,而不是 HttpClient。 (4认同)
  • 处理程序可能会从using语句中删除,它将在处理http客户端时被处理。 (2认同)
  • 如果 cookie 是基于用户的,并且根据请求而变化,请使用下面 Greg Beech 的答案。通过这种方式,您可以重用相同的 httpclient,而无需考虑 cookie 值的竞争条件。 (2认同)

Gre*_*ech 301

在大多数情况下,接受的答案是正确的方法.但是,在某些情况下您需要手动设置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();
}
Run Code Online (Sandbox Code Playgroud)

  • 我一直在追逐几天发送错误,其中SendAsync发送的请求没有发送cookie标头; 这有助于我意识到,除非你在Handler中设置UseCookies = false,否则它不仅会使用CookieContainer,还会_silently ignore_存储在请求标头中的任何Cookie!非常感谢! (40认同)
  • 这个答案对于任何试图使用HttpClient作为代理的人都非常有帮助! (12认同)
  • 注意:如果您只使用1个HttpClient实例来执行多个请求,则使用CookieContainer的cookie将被缓存.用户从另一个用户获取cookie是危险的. (9认同)
  • 当有人试图添加"Cookie"标头而不是默默地丢失它时,这个愚蠢的事情应该抛出异常.花了我一个小时的生命.谢谢你的解决方案. (8认同)
  • @AcazSouza 这不是这个答案的问题,因为它禁用了 CookieContainer 以便能够为每个请求发送自己的 cookie。 (3认同)
  • 立即尝试...如果可行,您应该得到一个很好的加拿大拥抱。 (2认同)

Kev*_*evM 9

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

配置服务IServiceCollection

services.AddHttpClient("MyNamedClient").AddHeaderPropagation();
services.AddHeaderPropagation(options =>
{
    options.Headers.Add("Cookie");
});
Run Code Online (Sandbox Code Playgroud)

配置为IApplicationBuilder

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


Waq*_*Haq 6

对我来说,简单的解决方案可以在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);
}
Run Code Online (Sandbox Code Playgroud)

  • 这适用于 C# 6.0 - 无需在 `HttpClientHandler` 上设置 `UseCookies=false` (3认同)
  • 但您实际上并没有在答案中表明这一点,也没有解释差异或好处(这实际上也不是问题,但我并不担心这一点)。我并不是想表现得粗鲁,重要的是要清楚这个答案对谁有帮助,而其他人不会更好地帮助他们。 (2认同)
  • 我相信这个答案只有在“HttpClientHandler”上设置“UseCookies = false”时才有效,这是@GregBeech的[答案](/sf/answers/930105711/)的本质。 (2认同)

Ami*_*ily 5

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

首先,我使用 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;
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这基本上是相同的答案 [as this one](/sf/answers/930105711/),其中唯一与 cookie 相关的部分是最后添加的标题。请注意该答案中的所有警告 (5认同)