C#HttpClient或使用CookieContainer模拟登陆后HttpRequest不发送cookie的解决方法及原因

解决办法

在发送包含用户名和密码的POST请求后,得到了包含”Set-cookie”的HttpWebResponse,随后应当添加如下代码

//Cookies为CookieContainer对象,Response为HttpWebResponse对象
Uri Host = new Uri("http://example.cn");
foreach (Cookie cookie in Response.Cookies)
    cookies.SetCookies(Host, ("" + cookie.Name + "=" + cookie.Value));

原因

简单的说,这个问题的原因源于CookieContainer的设计不足,鲁棒性不够强。

这里我们来简单了解一下Cookie方面的知识,rfc6265第5.3节定义了浏览器存放每个Cookie时应该包括这些字段:name、value、expiry-time、domain等等,但并不是每个网站都设计在Set-cookie时向用户返回所有的字段,比如下图的情况就只返回了name、value、expiry三个字段

这里写图片描述

重点在于,如上图的Set-Cookie头缺省了domain字段,对于一般浏览器来说,当接收到了缺省domain的Set-Cookie字段时,会主动添加本次请求地址的Host上去。而CookieContainer设计之初并没有打算主动帮助用户添加被请求Url的Host进Cookies(大家都不知道为毛),于是在CookieContainer中发生的事情就是,当CookieContainer看到了domain缺省的Set-Cookie字段,就直接把request的Url添加进了Cookie。

这会造成什么结果?我们假设有一个Host为Http://example.cn ,当我们登陆时会向/user/login.php POST一段信息,然后该地址返回Cookies,但由于CookieContainer将该完整地址保存给了这些Cookies,于是这些Cookies会并且只会在访问Http://example.cn/user/login.php时被发送。这就造成了题目所说的问题。

而上面的代码做的工作就是为现有的CookieContainer手动添加在Host下设置的cookie,这样当我们访问/user/home.php或者任何其他子节点的时候,Cookies就能够正常发送了。

关于HttpClient

HttpClient类型保存Cookies时用的是一个Flag为Protect的CookieContainer对象,所以HttpClient也会遇到一模一样的问题,而且由于在这里对象是Protect的,所以不能手动修改,暂时不知道如何在HttpClient中解决这一问题。

参考链接

1、HttpWebRequest and CookieContainer - login to a website
2、HttpWebRequest with CookieContainer problem in .NET 4+?

你可能感兴趣的:(net)