Here's how you could set a custom cookie value for the request:
下面是如何为请求设置自定义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();
}
The accepted answer is the correct way to do this in most cases. However, there are some situations where you want to set the cookie header manually. Normally if you set a "Cookie" header it is ignored, but that's because HttpClientHandler
defaults to using its CookieContainer
property for cookies. If you disable that then by setting UseCookies
to false
you can set cookie headers manually and they will appear in the request, e.g.
在大多数情况下,公认的答案是这样做的正确方式。但是,在某些情况下,您需要手动设置Cookie标头。通常,如果您设置了一个“Cookie”头,它将被忽略,但这是因为HttpClientHandler默认使用其CookieContainer属性来处理Cookie。如果禁用该功能,则可以通过将UseCookie设置为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();
}
For me the simple solution works to set cookies in HttpRequestMessage object.
对我来说,简单的解决方案是在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);
}
I had a similar problem and for my AspNetCore 3.1 application the other answers to this question were not working. I found that configuring a named HttpClient in my Startup.cs
and using header propagation of the Cookie header worked perfectly. It also avoids all the concerns about proper disposition of your handler and client. Note if propagation of the request cookies is not what you need (sorry Op) you can set your own cookies when configuring the client factory.
我遇到了类似的问题,对于我的AspNetCore3.1应用程序,这个问题的其他答案都不起作用。我发现在我的Startup.cs中配置一个命名的HttpClient并使用Cookie头的头传播非常有效。它还避免了所有关于正确处理您的处理程序和客户的担忧。注如果请求Cookie的传播不是您需要的(对不起,Op),您可以在配置客户端工厂时设置您自己的Cookie。
Configure Services with IServiceCollection
services.AddHttpClient("MyNamedClient").AddHeaderPropagation();
services.AddHeaderPropagation(options =>
{
options.Headers.Add("Cookie");
});
Configure with IApplicationBuilder
builder.UseHeaderPropagation();
- Inject the
IHttpClientFactory
into your controller or middleware.
- Create your client
using var client = clientFactory.CreateClient("MyNamedClient");
After spending hours on this issue, none of the answers above helped me so I found a really useful tool.
在这个问题上花了几个小时,上面的答案都对我没有帮助,所以我找到了一个真正有用的工具。
Firstly, I used Telerik's Fiddler 4 to study my Web Requests in details
首先,我使用Telerik的Fiddler 4详细研究了我的Web请求
Secondly, I came across this useful plugin for Fiddler:
其次,我发现了Fiddler的这个有用的插件:
https://github.com/sunilpottumuttu/FiddlerGenerateHttpClientCode
Https://github.com/sunilpottumuttu/FiddlerGenerateHttpClientCode
It will just generate the C# code for you. An example was:
它只会为您生成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;
Note that I had to comment out two lines as this plugin is not totally perfect yet but it did the job nevertheless.
请注意,我不得不注释掉两行,因为这个插件还不是完全完美,但它仍然完成了工作。
DISCLAIMER: I am not associated or endorsed by either Telerik or the plugin's author in anyway.
免责声明:我与Telerik或该插件的作者都没有任何关联或认可。
If you want to use HttpClient
to send a request that require the user to be logged in, this means you need to do the login process then receive the cookies and send these cookies to the request that require login.
如果您想使用HttpClient发送要求用户登录的请求,这意味着您需要执行登录过程,然后接收Cookie并将这些Cookie发送到需要登录的请求。
I did this in testing an Action called IsLoggedIn. This action checks if the user is logged using the cookies in the HttpRequest.
我在测试一个名为IsLoggedIn的操作时这样做了。此操作检查用户是否使用HttpRequest中的Cookie登录。
What I did in testing this action is:
我在测试此操作时所做的是:
string Login = JsonConvert.SerializeObject(new LoginViewModel()
{
Email = userFromDb.Email,
Password = "****",
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);
var cookies = new CookieContainer();
var clientHandler = new HttpClientHandler();
clientHandler.CookieContainer = cookies;
var client = new HttpClient(clientHandler, true);
更多回答
CAUTION: if you use just 1 instance of HttpClient to do several requests, cookies using CookieContainer is going cached. Is dangerous to a user get the cookie from another user.
注意:如果您只使用HttpClient的一个实例来执行多个请求,则使用CookieContainer的Cookie将被缓存。从另一个用户那里获取Cookie对用户来说是危险的。
"HttpClient is intended to be instantiated once and re-used throughout the life of an application. Especially in server applications, creating a new HttpClient instance for every request will exhaust the number of sockets available under heavy loads..." From here: asp.net/web-api/overview/advanced/…
HttpClient旨在实例化一次,并在应用程序的整个生命周期中重复使用。特别是在服务器应用程序中,为每个请求创建一个新的HttpClient实例将耗尽在高负载下可用的套接字数量...从此处开始:ASP.NET/Web-API/概述/高级/…
@SergeyT so what does one do when he needs to make separate-session calls to the same resource? :)
@SergeyT那么,当需要对同一资源进行单独的会话调用时,该怎么办?:)
@RobertMcLaws not in the use-case as shown here. However, in discussions on the .NET GitHub it was brought to my attention that the problem does not lie in the HttpClient being disposed, but rather the HttpClientHandler. If you keep a static instance of the HttpClientHandler and pass that to the HttpClient constructor with disposeHandler
set to false, you can create and dispose however many HttpClient instances you like, as it's actually the HttpMessageHandler that owns the resources, and not HttpClient.
@RobertMcLaws不在用例中,如下所示。然而,在有关.NET GitHub的讨论中,我注意到问题不在于正在处理的HttpClient,而在于HttpClientHandler。如果保留HttpClientHandler的静态实例,并将其传递到disposeHandler设置为False的HttpClient构造函数,则可以创建和处置任意数量的HttpClient实例,因为实际上拥有资源的是HttpMessageHandler,而不是HttpClient。
I've been chasing for several days an error in which requests sent with SendAsync did not send the cookie header; this helped me realize that, unless you set UseCookies = false in the Handler, it will not only use the CookieContainer, but also silently ignore any Cookie stored in the request headers! Thank you so much!
几天来,我一直在追踪一个错误,其中使用SendAsync发送的请求没有发送Cookie标头;这帮助我意识到,除非在处理程序中设置UseCookies=False,否则它不仅会使用CookieContainer,还会自动忽略请求标头中存储的任何Cookie!非常感谢!
This answer is extremely helpful for anyone trying to use HttpClient as a proxy!
这个答案对任何试图使用HttpClient作为代理的人都非常有帮助!
CAUTION: if you use just 1 instance of HttpClient to do several requests, cookies using CookieContainer is going cached. Is dangerous to a user get the cookie from another user.
注意:如果您只使用HttpClient的一个实例来执行多个请求,则使用CookieContainer的Cookie将被缓存。从另一个用户那里获取Cookie对用户来说是危险的。
That stupid thing should throw an exception when someone tries to add a "Cookie" header instead of silently loosing it. Cost me an hour of my life. Thanks for the solution.
当有人试图添加一个“Cookie”头而不是静静地丢失它时,这个愚蠢的东西应该抛出一个异常。耗费了我生命中的一个小时。谢谢你的解决方案。
@AcazSouza this is a non-issue for this answer, as it disables the CookieContainer to be able to send its own cookies per request.
@AcazSouza这对于这个答案来说不是问题,因为它使CookieContainer无法根据请求发送自己的Cookie。
Note that the accepted answer does a ton more and handles a lot more edge conditions than this. It can be used to do things like http only or scoped cookies, multivalue cookies, etc etc. The second highest rated answer proposes the same method as this but with a lot more context and explanation
请注意,可接受的答案所做的工作更多,处理的边缘条件也比这多得多。它可以用来做一些事情,如仅http或作用域cookie、多值cookie等。评分第二高的答案提出了与此相同的方法,但有更多上下文和解释
@GeorgeMauer may be you are right. Both of them creating httpClient from "HttpClient(handler)". In my case I'm creating _httpClient from httpClientPool.GetOrCreateHttpClient()
@GeorgeMauer也许你是对的。他们都是从“HttpClient(Handler)”创建HTTPClient的。在我的例子中,我从HTTPClientPool.GetOrCreateHttpClient()创建_HTTpClient
But you don't actually show that in your answer nor explain the difference or the benefits (it also is not actually the question, but I'm not worried about that). I'm not trying to be rude, its just important to be clear who this answer would be helpful to that would not be better helped by the others.
但你实际上没有在你的回答中说明这一点,也没有解释其中的区别或好处(这也不是实际上的问题,但我并不担心)。我不是想无礼,重要的是要弄清楚这个答案对谁会有帮助,其他人也不会有更好的帮助。
I believe this answer only works if you set UseCookies = false
on the HttpClientHandler
, which is the essence of @GregBeech's answer.
我相信只有当您在HttpClientHandler上设置UseCookies=False时,这个答案才有效,这是@GregBeech答案的本质。
This works for me with C# 6.0 - no need to set UseCookies=false
on the HttpClientHandler
这适用于我的C#6.0-不需要在HttpClientHandler上设置UseCookies=False
Will using services.AddHeaderPropagation(options, add http cookies to subsequent requests?
是否会使用services.AddHeaderPropagation(选项,将http cookie添加到后续请求?
This is essentially the same answer as this one, the only part of it that has to do with cookies is that last addition of a header. Note all the caveats in that answer
这基本上与这个答案相同,唯一与Cookie有关的部分是最后添加的头。请注意答案中的所有注意事项
我是一名优秀的程序员,十分优秀!