CookieContainer 对象可以用于在 HTTP 请求间传递 Cookie 信息。如果我们需要向 CookieContainer 中添加一条数据,可以采用其 Add 方法:
var cookieContainer = new CookieContainer();
cookieContainer.Add(new Cookie("name", "Soar360", "/", "httpbin.org"));
using (var handler = new HttpClientHandler
{
UseCookies = true,
CookieContainer = cookieContainer
})
{
using (var http = new HttpClient(handler))
{
var json = await http.GetStringAsync("https://httpbin.org/cookies");
Console.WriteLine(json);
}
}
以上代码的输出如下:
{
"cookies": {
"name": "Soar360"
}
}
有时我们需要将 CookieContainer 进行持久化(序列化),将其保存到本地文件或数据库中(比如当 Cookie 包含了对某个资源的访问凭据时)。很长一段时间中,我们只能通过反射来实现该功能:
public static CookieCollection GetAllCookies(CookieContainer cookieJar)
{
CookieCollection cookieCollection = new CookieCollection();
Hashtable table = (Hashtable) cookieJar.GetType().InvokeMember("m_domainTable",
BindingFlags.NonPublic |
BindingFlags.GetField |
BindingFlags.Instance,
null,
cookieJar,
new object[] {});
foreach (var tableKey in table.Keys)
{
String str_tableKey = (string) tableKey;
if (str_tableKey[0] == '.')
{
str_tableKey = str_tableKey.Substring(1);
}
SortedList list = (SortedList) table[tableKey].GetType().InvokeMember("m_list",
BindingFlags.NonPublic |
BindingFlags.GetField |
BindingFlags.Instance,
null,
table[tableKey],
new object[] { });
foreach (var listKey in list.Keys)
{
String url = "https://" + str_tableKey + (string) listKey;
cookieCollection.Add(cookieJar.GetCookies(new Uri(url)));
}
}
return cookieCollection;
}
测试代码:
CookieContainer cookieContainer = new CookieContainer();
cookieContainer.Add(new Cookie("name1", "value1", "/", ".coderbusy.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/", ".coderbusy.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/path2/", ".coderbusy.com"));
cookieContainer.Add(new Cookie("name1", "value1", "/", ".sum16.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/", ".sum16.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/path2/", ".sum16.com"));
CookieCollection cookies = GetAllCookies(cookieContainer);
Console.WriteLine(JsonConvert.SerializeObject(cookies, Newtonsoft.Json.Formatting.Indented));
输出:
[
{
"Comment": "",
"CommentUri": null,
"HttpOnly": false,
"Discard": false,
"Domain": ".coderbusy.com",
"Expired": false,
"Expires": "0001-01-01T00:00:00",
"Name": "name2",
"Path": "/path1/path2/",
"Port": "",
"Secure": false,
"TimeStamp": "2021-11-13T11:31:20.3900972+08:00",
"Value": "value1",
"Version": 0
},...
]
幸运的是,随着 .NET 6 的正式发布,CookieContainer 类型新增了一个名为 GetAllCookies() 的实例方法,该方法可以获取到 CookieContainer 中所有的 Cookie 信息,并填充 CookieCollection 。所以测试代码可以改为:
CookieContainer cookieContainer = new CookieContainer();
cookieContainer.Add(new Cookie("name1", "value1", "/", ".coderbusy.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/", ".coderbusy.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/path2/", ".coderbusy.com"));
cookieContainer.Add(new Cookie("name1", "value1", "/", ".sum16.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/", ".sum16.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/path2/", ".sum16.com"));
CookieCollection cookies = cookieContainer.GetAllCookies();
Console.WriteLine(JsonConvert.SerializeObject(cookies, Newtonsoft.Json.Formatting.Indented));
该代码会产生同样的输出,但明显更加直观和优雅。










