如何在httpclient的HttpRequestMessage上设置cookie

我试图使用web api的HttpClient做一个post到一个端点,需要登录的形式是一个标识帐户的HTTP cookie(这只是一些是#ifdef'ed的发布版本)。

如何将cookie添加到HttpRequestMessage?

269088 次浏览

下面是如何为请求设置自定义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();
}

在大多数情况下,接受的答案是正确的方法。但是,在某些情况下,您需要手动设置cookie报头。通常情况下,如果你设置了“Cookie”标头,它会被忽略,但这是因为HttpClientHandler默认为Cookie使用其CookieContainer属性。如果你禁用它,那么通过设置UseCookiesfalse,你可以手动设置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();
}

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

首先,我使用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或插件作者没有任何联系或认可。

对我来说,简单的解决方案是在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);
}

我遇到过类似的问题,对于我的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");

如果你想使用HttpClient来发送一个要求用户登录的请求,这意味着你需要完成登录过程,然后接收cookie,并将这些cookie发送到需要登录的请求。

我在测试一个名为IsLoggedIn的动作时做到了这一点。该操作检查用户是否使用HttpRequest中的cookie进行了登录。

我在测试这个动作时所做的是:

                string Login = JsonConvert.SerializeObject(new LoginViewModel()
{
Email = userFromDb.Email,
Password = "fdfdf@2239",
RememberMe = false
}); ;
StringContent LoginhttpContent = new(Login, Encoding.UTF8, "application/json");
var Login_response = await _httpClient.PostAsync(HelperFunctions.getUrl(HelperFunctions.AcctounController.name, HelperFunctions.AcctounController.Login), LoginhttpContent);
Assert.Equal(HttpStatusCode.OK, Login_response.StatusCode);
    

//receive cookies from the login response
var cookies = Login_response.Headers.GetValues(HeaderNames.SetCookie);
//Add the cookies to the DefaultRequestHeaders of the _httpClient
_httpClient.DefaultRequestHeaders.Add("Cookie",cookies);
var IsLoggedIn_response = await _httpClient.GetAsync(HelperFunctions.getUrl(HelperFunctions.AcctounController.name, HelperFunctions.AcctounController.IsLoggedIn));
Assert.Equal("true",IsLoggedIn_response.Content.ReadAsStringAsync().Result);