在 HttpClient 中使用 Cookie
Cookie 是服务器存储在客户端的小型数据片段,可用于身份验证、会话跟踪等。
.Net HttpClient 支持 Cookie 功能,本教程详细介绍了Cookie 的管理与使用。
初始化
#!import "./Ini.ipynb"
什么是 Cookie
Cookie 是服务器发送到用户浏览器并存储在本地的一小段数据,用来进行会话管理(如登录状态)、个性化设置(如主题偏好)、跟踪用户行为等功能。
HttClient 手动管理 Cookie
如果只在简单的使用Cookie,想保持简洁、灵活。可以手管理。
发送带Cookie的请求
- 不使用Cookie
{ //不使用Cookie
using (var client = new HttpClient(){BaseAddress=new Uri(webApiBaseUrl)})
{
var response = await client.GetAsync("/api/Cookie/GetRequestCookie");
//确保请求成功
response.EnsureSuccessStatusCode();
//读取响应内容
var content = await response.Content.ReadAsStringAsync();
//输出 响应内容
Console.WriteLine(content);
}
}
- 手动设置Cookie: 在默认请求头中添加Cookie,适合快捷请求方法(Get,Post,Put,Delete等)
{ //多次请求时,都自动携带默认请求头Cookie
var client = new HttpClient()
{
BaseAddress = new Uri(webApiBaseUrl),
};
//全局设置Cookie,所有快捷请求(Send方法的快捷方法:Get、Post、Put等)都会带上这个Cookie
//快捷方法,不能单独设置Cookie; 只有Send方法才可以单独设置Cookie
client.DefaultRequestHeaders.Add("Cookie", "Client=PolyglotNotebook,User=andy");
//请求1
var response = await client.GetAsync("/api/Cookie/GetRequestCookie");
//确保请求成功
response.EnsureSuccessStatusCode();
//读取响应内容
var content = await response.Content.ReadAsStringAsync();
//输出 响应内容
Console.WriteLine(content);
//再次快捷请求,不用重新设置
//请求2
var response2 = await client.GetAsync("/api/Cookie/GetRequestCookie");
//确保请求成功
response2.EnsureSuccessStatusCode();
//读取响应内容
var content2 = await response2.Content.ReadAsStringAsync();
//输出 响应内容
Console.WriteLine(content2);
}
- 手动设置Cookie:每次请求设置 HttpRequestMessage,适合Send通用方法。当然可以合并默认请求头
{ //手动设置Cookie, 单次HttpRequestMessage合并默认请求头Cookie
var client = new HttpClient()
{
BaseAddress = new Uri(webApiBaseUrl),
};
//全局设置Cookie,所有请求都会带上这个Cookie
client.DefaultRequestHeaders.Add("Cookie", "Client=PolyglotNotebook,User=andy");
//单请求设置
var requestMessage = new HttpRequestMessage(HttpMethod.Get, "/api/Cookie/GetRequestCookie");
//设置Cookie,会覆盖HttpClient设置的默认Cookie
requestMessage.Headers.Add("Cookie", "Password=MyPassword,Role=Admin");
//添加默认
if(client.DefaultRequestHeaders.Contains("Cookie"))
{
requestMessage.Headers.Add("Cookie", client.DefaultRequestHeaders.GetValues("Cookie"));
}
var response = await client.SendAsync(requestMessage);
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
//响应头也会自动带上Cookie
if(response.Headers.Contains("cookie"))
{
Console.Write($"响应头中Cookie为:");
var cookies = response.Headers.GetValues("cookie");
foreach (var cookie in cookies)
{
Console.WriteLine($"{cookie}");
}
}
else
{
Console.WriteLine($"响应头中没有Cookie");
}
}
查看响应头中的Cookie
{ //获取响应头中的Cookie
var client = new HttpClient()
{
BaseAddress = new Uri(webApiBaseUrl),
};
var response = await client.GetAsync("/api/Cookie/GetResponseCookie");
//获取响应头中的Cookie
if(response.Headers.Contains("cookie"))
{
Console.Write($"响应头中Cookie为:");
var cookies = response.Headers.GetValues("cookie");
foreach (var cookie in cookies)
{
Console.WriteLine($"{cookie}");
}
}
else
{
Console.WriteLine($"响应头中没有Cookie");
}
}
HttClient 使用 CookieContainer 自动管理 Cookie
.NET 提供了 HttpClientHandler + CookieContainer 来自动管理 Cookie 生命周期和持久化。
使用 CookieContainer
{
var handler = new HttpClientHandler()
{
UseCookies = true,
CookieContainer = new CookieContainer(),
};
using var client = new HttpClient(handler)
{
BaseAddress = new Uri(webApiBaseUrl),
};
// 第一次请求,服务端设置 Cookie
var response = await client.GetAsync("/api/Cookie/GetResponseCookie");
response.EnsureSuccessStatusCode();
// 第二次请求,自动携带之前设置的 Cookie
var response2 = await client.GetAsync("/api/Cookie/GetRequestCookie");
var content2 = await response2.Content.ReadAsStringAsync();
Console.WriteLine(content2);
}
Cookie 持久化(保存与恢复)
若需要在程序重启后继续使用 Cookie,可将其序列化保存至文件或数据库。
- 保存 Cookie 到文件
///<summary
/// 保存Cookie到文件
///</summary>
public void SaveCookies(CookieContainer container, string filePath)
{
using (var writer = new StreamWriter(filePath))
{
foreach (Cookie cookie in container.GetCookies(new Uri(webApiBaseUrl)))
{
writer.WriteLine($"{cookie.Name}={cookie.Value};Domain={cookie.Domain};Path={cookie.Path};Expires={cookie.Expires}");
}
}
}
//应用
{
var handler = new HttpClientHandler()
{
UseCookies = true,
CookieContainer = new CookieContainer(),
};
using (var client = new HttpClient(handler))
{
client.BaseAddress = new Uri(webApiBaseUrl);
// 第一次请求,服务端设置 Cookie
var response = await client.GetAsync("/api/Cookie/GetResponseCookie");
response.EnsureSuccessStatusCode();
SaveCookies(handler.CookieContainer, "cookies.txt");
}
}
- 从文件中加载 Cookie
<summary>
/// 从文件中加载 Cookie
/// </summary>
public CookieContainer LoadCookies(string filePath)
{
var container = new CookieContainer();
if (!File.Exists(filePath)) return container;
foreach (var line in File.ReadAllLines(filePath))
{
var parts = line.Split(';');
var nameValue = parts[0].Split('=');
var cookie = new Cookie(nameValue[0], nameValue[1])
{
Domain = parts[1].Replace("Domain=", "").Trim(),
Path = parts[2].Replace("Path=", "").Trim(),
Expires = DateTime.Parse(parts[3].Replace("Expires=", "").Trim())
};
container.Add(cookie);
}
return container;
}
//发送请求:从文件中加载 Cookie, 在请求中携带
{
var cookieBox = LoadCookies("cookies.txt");
var handler = new HttpClientHandler()
{
UseCookies = true,
CookieContainer = cookieBox,
};
var client = new HttpClient(handler)
{
BaseAddress = new Uri(webApiBaseUrl)
};
// 第一次请求,服务端设置 Cookie
var response = await client.GetAsync("/api/Cookie/GetRequestCookie");
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
}
跨域 Cookie 处理
默认情况下,CookieContainer 会根据域名自动隔离 Cookie。若需跨域共享 Cookie,可通过以下方式实现:
- 手动复制 Cookie
//示例代码,无实际请求
var sourceUri = new Uri("https://source.com");
var targetUri = new Uri("https://target.com");
foreach (Cookie cookie in handler.CookieContainer.GetCookies(sourceUri))
{
var crossDomainCookie = new Cookie(cookie.Name, cookie.Value, cookie.Path, targetUri.Host);
handler.CookieContainer.Add(targetUri, crossDomainCookie);
}
- 自定义 CookieContainer(高级)
可以继承 CookieContainer 并重写相关方法以实现自定义 Cookie 共享策略。
进阶功能:Cookie 过期、安全标志、SameSite 设置等
- 设置 Cookie 高级属性
{
//发送请求
{
var handler = new HttpClientHandler()
{
UseCookies = true,
CookieContainer = new CookieContainer(),
};
var client = new HttpClient(handler)
{
BaseAddress = new Uri(webApiBaseUrl)
};
//设置Cookie
var cookie = new Cookie("jwt_token", "a.b.c")
{
Expires = DateTime.Now.AddDays(7),
Domain = new Uri(webApiBaseUrl).Host,
Path = "/",
Secure = true, // 仅 HTTPS 传输
HttpOnly = true, // 防止 XSS 攻击
};
handler.CookieContainer.Add(new Uri(webApiBaseUrl), cookie);
// 第一次请求,服务端设置 Cookie
var response = await client.GetAsync("/api/Cookie/GetRequestCookie");
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
}
}
总结
功能 | 描述 | 适用场景 |
---|---|---|
手动设置 Cookie | 灵活、简单 | 单次请求或固定 Cookie |
使用 HttpRequestMessage | 更精细控制 Cookie 行为 | 需要合并默认与自定义 Cookie |
使用 CookieContainer | 自动管理 Cookie 生命周期 | 多次请求、需要保持会话状态 |
Cookie 持久化 | 保存 Cookie 至文件或数据库 | 程序重启后仍需保持登录状态 |
跨域 Cookie | 手动复制或自定义容器 | 需要在多个域名之间共享 Cookie |
安全 Cookie 设置 | Secure 、HttpOnly 、SameSite |
增强 Cookie 安全性 |
获取 Cookie 属性 | 查看 Cookie 的有效期、路径等信息 | 调试和日志记录 |