You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
HttpClientStudy/Docs/1.3.7.基础使用.使用Cookie.ipynb

760 lines
24 KiB
Plaintext

1 year ago
{
2 months ago
"cells": [
{
"cell_type": "markdown",
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"source": [
"在 HttpClient 中使用 Cookie\n",
"============================="
]
1 year ago
},
2 months ago
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Cookie 是服务器存储在客户端的小型数据片段,可用于身份验证、会话跟踪等。\n",
"\n",
".Net HttpClient 支持 Cookie 功能本教程详细介绍了Cookie 的管理与使用。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 初始化"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"data": {
"text/markdown": [
"## 初始化\n",
"这是全局共用文件包括Nuget包引用、全局类库引用、全局文件引用、全局命名空间引用、全局变量、全局方法、全局类定义等功能。\n",
"\n",
"在业务笔记中引用,执行其它单元格之前先执行一次。"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Microsoft.Extensions.DependencyInjection, 9.0.5</span></li><li><span>Microsoft.Extensions.Http, 9.0.5</span></li><li><span>Microsoft.Extensions.Http.Polly, 9.0.5</span></li><li><span>Microsoft.Extensions.Logging, 9.0.5</span></li><li><span>Microsoft.Extensions.Logging.Console, 9.0.5</span></li><li><span>Microsoft.Net.Http.Headers, 9.0.5</span></li><li><span>Polly, 8.5.2</span></li><li><span>Refit, 8.0.0</span></li><li><span>Refit.HttpClientFactory, 8.0.0</span></li><li><span>System.Net.Http.Json, 9.0.5</span></li></ul></div></div>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"配置文件根目录c:\\Users\\ruyu\\Desktop\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.Core\n",
"配置文件根目录c:\\Users\\ruyu\\Desktop\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.Core\n",
"启动WebApi项目...\n",
"程序[c:\\Users\\ruyu\\Desktop\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.WebApp\\HttpClientStudy.WebApp.exe]已在新的命令行窗口执行。如果未出现新命令行窗口,可能是程序错误造成窗口闪现!\n",
"已启动WebApi项目,保持窗口打开状态!\n",
"初始化完成!\n"
]
}
],
"source": [
"#!import \"./Ini.ipynb\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 什么是 Cookie"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> Cookie 是服务器发送到用户浏览器并存储在本地的一小段数据,用来进行会话管理(如登录状态)、个性化设置(如主题偏好)、跟踪用户行为等功能。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## HttClient 手动管理 Cookie"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"如果只在简单的使用Cookie想保持简洁、灵活。可以手管理。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 发送带Cookie的请求"
]
},
{
"cell_type": "markdown",
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"source": [
"+ 不使用Cookie"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\"data\":\"\",\"code\":1,\"message\":\"没有Cookie\"}\r\n"
]
}
],
"source": [
"{ //不使用Cookie\n",
" using (var client = new HttpClient(){BaseAddress=new Uri(webApiBaseUrl)})\n",
" {\n",
" var response = await client.GetAsync(\"/api/Cookie/GetRequestCookie\"); \n",
"\n",
" //确保请求成功\n",
" response.EnsureSuccessStatusCode();\n",
"\n",
" //读取响应内容\n",
" var content = await response.Content.ReadAsStringAsync();\n",
"\n",
" //输出 响应内容\n",
" Console.WriteLine(content);\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"+ 手动设置Cookie: 在默认请求头中添加Cookie适合快捷请求方法(Get,Post,Put,Delete等)\n"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\"data\":[{\"key\":\"Client\",\"value\":\"PolyglotNotebook\"},{\"key\":\"User\",\"value\":\"andy\"}],\"code\":1,\"message\":\"成功\"}\n",
"{\"data\":[{\"key\":\"Client\",\"value\":\"PolyglotNotebook\"},{\"key\":\"User\",\"value\":\"andy\"}],\"code\":1,\"message\":\"成功\"}\n"
]
}
],
"source": [
"{ //多次请求时都自动携带默认请求头Cookie\n",
"\n",
" var client = new HttpClient()\n",
" {\n",
" BaseAddress = new Uri(webApiBaseUrl),\n",
" };\n",
"\n",
" //全局设置Cookie,所有快捷请求(Send方法的快捷方法Get、Post、Put等)都会带上这个Cookie\n",
" //快捷方法不能单独设置Cookie; 只有Send方法才可以单独设置Cookie\n",
" client.DefaultRequestHeaders.Add(\"Cookie\", \"Client=PolyglotNotebook,User=andy\");\n",
"\n",
" //请求1\n",
" var response = await client.GetAsync(\"/api/Cookie/GetRequestCookie\"); \n",
"\n",
" //确保请求成功\n",
" response.EnsureSuccessStatusCode();\n",
"\n",
" //读取响应内容\n",
" var content = await response.Content.ReadAsStringAsync();\n",
"\n",
" //输出 响应内容\n",
" Console.WriteLine(content);\n",
"\n",
" //再次快捷请求,不用重新设置\n",
" //请求2\n",
" var response2 = await client.GetAsync(\"/api/Cookie/GetRequestCookie\"); \n",
"\n",
" //确保请求成功\n",
" response2.EnsureSuccessStatusCode();\n",
"\n",
" //读取响应内容\n",
" var content2 = await response2.Content.ReadAsStringAsync();\n",
"\n",
" //输出 响应内容\n",
" Console.WriteLine(content2);\n",
"\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"+ 手动设置Cookie每次请求设置 HttpRequestMessage适合Send通用方法。当然可以合并默认请求头"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\"data\":[{\"key\":\"Password\",\"value\":\"MyPassword\"},{\"key\":\"Role\",\"value\":\"Admin\"},{\"key\":\"Client\",\"value\":\"PolyglotNotebook\"},{\"key\":\"User\",\"value\":\"andy\"}],\"code\":1,\"message\":\"成功\"}\n",
"响应头中没有Cookie\n"
]
}
],
"source": [
"{ //手动设置Cookie, 单次HttpRequestMessage合并默认请求头Cookie\n",
"\n",
" var client = new HttpClient()\n",
" {\n",
" BaseAddress = new Uri(webApiBaseUrl),\n",
" };\n",
"\n",
" //全局设置Cookie,所有请求都会带上这个Cookie\n",
" client.DefaultRequestHeaders.Add(\"Cookie\", \"Client=PolyglotNotebook,User=andy\");\n",
"\n",
" //单请求设置\n",
" var requestMessage = new HttpRequestMessage(HttpMethod.Get, \"/api/Cookie/GetRequestCookie\");\n",
" \n",
" //设置Cookie会覆盖HttpClient设置的默认Cookie\n",
" requestMessage.Headers.Add(\"Cookie\", \"Password=MyPassword,Role=Admin\");\n",
" //添加默认\n",
" if(client.DefaultRequestHeaders.Contains(\"Cookie\"))\n",
" {\n",
" requestMessage.Headers.Add(\"Cookie\", client.DefaultRequestHeaders.GetValues(\"Cookie\"));\n",
" }\n",
"\n",
" var response = await client.SendAsync(requestMessage);\n",
" var content = await response.Content.ReadAsStringAsync();\n",
" Console.WriteLine(content);\n",
"\n",
" //响应头也会自动带上Cookie\n",
" if(response.Headers.Contains(\"cookie\"))\n",
" {\n",
" Console.Write($\"响应头中Cookie为\");\n",
" var cookies = response.Headers.GetValues(\"cookie\");\n",
" foreach (var cookie in cookies)\n",
" {\n",
" Console.WriteLine($\"{cookie}\");\n",
" }\n",
" }\n",
" else\n",
" {\n",
" Console.WriteLine($\"响应头中没有Cookie\");\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 查看响应头中的Cookie"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"响应头中没有Cookie\r\n"
]
}
],
"source": [
"{ //获取响应头中的Cookie\n",
"\n",
" var client = new HttpClient()\n",
" {\n",
" BaseAddress = new Uri(webApiBaseUrl),\n",
" };\n",
"\n",
" var response = await client.GetAsync(\"/api/Cookie/GetResponseCookie\");\n",
"\n",
" //获取响应头中的Cookie\n",
" if(response.Headers.Contains(\"cookie\"))\n",
" {\n",
" Console.Write($\"响应头中Cookie为\");\n",
" var cookies = response.Headers.GetValues(\"cookie\");\n",
" foreach (var cookie in cookies)\n",
" {\n",
" Console.WriteLine($\"{cookie}\");\n",
" }\n",
" }\n",
" else\n",
" {\n",
" Console.WriteLine($\"响应头中没有Cookie\");\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## HttClient 使用 CookieContainer 自动管理 Cookie"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
".NET 提供了 HttpClientHandler + CookieContainer 来自动管理 Cookie 生命周期和持久化。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 使用 CookieContainer"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\"data\":[{\"key\":\"ProjectName\",\"value\":\"WebApp\"},{\"key\":\"Version\",\"value\":\"Dotnet9\"}],\"code\":1,\"message\":\"成功\"}\r\n"
]
}
],
"source": [
"{\n",
" var handler = new HttpClientHandler()\n",
" {\n",
" UseCookies = true,\n",
" CookieContainer = new CookieContainer(),\n",
" };\n",
"\n",
" using var client = new HttpClient(handler)\n",
" {\n",
" BaseAddress = new Uri(webApiBaseUrl),\n",
" };\n",
"\n",
" // 第一次请求,服务端设置 Cookie\n",
" var response = await client.GetAsync(\"/api/Cookie/GetResponseCookie\");\n",
" response.EnsureSuccessStatusCode();\n",
"\n",
" // 第二次请求,自动携带之前设置的 Cookie\n",
" var response2 = await client.GetAsync(\"/api/Cookie/GetRequestCookie\");\n",
" var content2 = await response2.Content.ReadAsStringAsync();\n",
" Console.WriteLine(content2);\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Cookie 持久化(保存与恢复)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"若需要在程序重启后继续使用 Cookie可将其序列化保存至文件或数据库。"
]
},
{
"cell_type": "markdown",
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"source": [
"+ 保存 Cookie 到文件"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"///<summary\n",
"/// 保存Cookie到文件\n",
"///</summary>\n",
"public void SaveCookies(CookieContainer container, string filePath)\n",
"{\n",
" using (var writer = new StreamWriter(filePath))\n",
" {\n",
" foreach (Cookie cookie in container.GetCookies(new Uri(webApiBaseUrl)))\n",
" {\n",
" writer.WriteLine($\"{cookie.Name}={cookie.Value};Domain={cookie.Domain};Path={cookie.Path};Expires={cookie.Expires}\");\n",
" }\n",
" }\n",
"}\n",
"\n",
"//应用\n",
"{\n",
" var handler = new HttpClientHandler()\n",
" {\n",
" UseCookies = true,\n",
" CookieContainer = new CookieContainer(),\n",
" };\n",
"\n",
" using (var client = new HttpClient(handler))\n",
" {\n",
" client.BaseAddress = new Uri(webApiBaseUrl);\n",
"\n",
" // 第一次请求,服务端设置 Cookie\n",
" var response = await client.GetAsync(\"/api/Cookie/GetResponseCookie\");\n",
" response.EnsureSuccessStatusCode();\n",
"\n",
" SaveCookies(handler.CookieContainer, \"cookies.txt\");\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"+ 从文件中加载 Cookie"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\"data\":[{\"key\":\"ProjectName\",\"value\":\"WebApp\"},{\"key\":\"Version\",\"value\":\"Dotnet9\"}],\"code\":1,\"message\":\"成功\"}\r\n"
]
}
],
"source": [
"//// <summary>\n",
"/// 从文件中加载 Cookie\n",
"/// </summary>\n",
"public CookieContainer LoadCookies(string filePath)\n",
"{\n",
" var container = new CookieContainer();\n",
" if (!File.Exists(filePath)) return container;\n",
"\n",
" foreach (var line in File.ReadAllLines(filePath))\n",
" {\n",
" var parts = line.Split(';');\n",
" var nameValue = parts[0].Split('=');\n",
" var cookie = new Cookie(nameValue[0], nameValue[1])\n",
" {\n",
" Domain = parts[1].Replace(\"Domain=\", \"\").Trim(),\n",
" Path = parts[2].Replace(\"Path=\", \"\").Trim(),\n",
" Expires = DateTime.Parse(parts[3].Replace(\"Expires=\", \"\").Trim())\n",
" };\n",
" container.Add(cookie);\n",
" }\n",
"\n",
" return container;\n",
"}\n",
"\n",
"//发送请求:从文件中加载 Cookie, 在请求中携带\n",
"{\n",
" var cookieBox = LoadCookies(\"cookies.txt\");\n",
"\n",
" var handler = new HttpClientHandler()\n",
" {\n",
" UseCookies = true,\n",
" CookieContainer = cookieBox,\n",
" };\n",
"\n",
" var client = new HttpClient(handler)\n",
" {\n",
" BaseAddress = new Uri(webApiBaseUrl)\n",
" };\n",
"\n",
" // 第一次请求,服务端设置 Cookie\n",
" var response = await client.GetAsync(\"/api/Cookie/GetRequestCookie\");\n",
" response.EnsureSuccessStatusCode();\n",
"\n",
" var content = await response.Content.ReadAsStringAsync();\n",
"\n",
" Console.WriteLine(content);\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 跨域 Cookie 处理"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"默认情况下CookieContainer 会根据域名自动隔离 Cookie。若需跨域共享 Cookie可通过以下方式实现"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"+ 手动复制 Cookie"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"//示例代码,无实际请求\n",
"var sourceUri = new Uri(\"https://source.com\");\n",
"var targetUri = new Uri(\"https://target.com\");\n",
"\n",
"foreach (Cookie cookie in handler.CookieContainer.GetCookies(sourceUri))\n",
"{\n",
" var crossDomainCookie = new Cookie(cookie.Name, cookie.Value, cookie.Path, targetUri.Host);\n",
" handler.CookieContainer.Add(targetUri, crossDomainCookie);\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"+ 自定义 CookieContainer高级"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"可以继承 CookieContainer 并重写相关方法以实现自定义 Cookie 共享策略。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 进阶功能Cookie 过期、安全标志、SameSite 设置等"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"+ 设置 Cookie 高级属性"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\"data\":\"\",\"code\":1,\"message\":\"没有Cookie\"}\r\n"
]
}
],
"source": [
"{\n",
" //发送请求\n",
" {\n",
" var handler = new HttpClientHandler()\n",
" {\n",
" UseCookies = true,\n",
" CookieContainer = new CookieContainer(),\n",
" };\n",
"\n",
" var client = new HttpClient(handler)\n",
" {\n",
" BaseAddress = new Uri(webApiBaseUrl)\n",
" };\n",
"\n",
" //设置Cookie\n",
" var cookie = new Cookie(\"jwt_token\", \"a.b.c\")\n",
" {\n",
" Expires = DateTime.Now.AddDays(7),\n",
" Domain = new Uri(webApiBaseUrl).Host,\n",
" Path = \"/\",\n",
" Secure = true, // 仅 HTTPS 传输\n",
" HttpOnly = true, // 防止 XSS 攻击\n",
" };\n",
"\n",
" handler.CookieContainer.Add(new Uri(webApiBaseUrl), cookie);\n",
"\n",
" // 第一次请求,服务端设置 Cookie\n",
" var response = await client.GetAsync(\"/api/Cookie/GetRequestCookie\");\n",
" response.EnsureSuccessStatusCode();\n",
"\n",
" var content = await response.Content.ReadAsStringAsync();\n",
"\n",
" Console.WriteLine(content);\n",
" }\n",
"}\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 总结"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"| 功能 | 描述 | 适用场景 |\n",
"|--------------------|--------------------------------------|--------------------------------------------|\n",
"| 手动设置 Cookie | 灵活、简单 | 单次请求或固定 Cookie |\n",
"| 使用 HttpRequestMessage | 更精细控制 Cookie 行为 | 需要合并默认与自定义 Cookie |\n",
"| 使用 CookieContainer | 自动管理 Cookie 生命周期 | 多次请求、需要保持会话状态 |\n",
"| Cookie 持久化 | 保存 Cookie 至文件或数据库 | 程序重启后仍需保持登录状态 |\n",
"| 跨域 Cookie | 手动复制或自定义容器 | 需要在多个域名之间共享 Cookie |\n",
"| 安全 Cookie 设置 | `Secure`、`HttpOnly`、`SameSite` | 增强 Cookie 安全性 |\n",
"| 获取 Cookie 属性 | 查看 Cookie 的有效期、路径等信息 | 调试和日志记录 |"
]
1 year ago
}
2 months ago
],
"metadata": {
"kernelspec": {
"display_name": ".NET (C#)",
"language": "C#",
"name": ".net-csharp"
1 year ago
},
2 months ago
"language_info": {
"name": "python"
1 year ago
},
2 months ago
"polyglot_notebook": {
"kernelInfo": {
"defaultKernelName": "csharp",
"items": [
{
"aliases": [],
"name": "csharp"
}
]
}
1 year ago
}
},
2 months ago
"nbformat": 4,
"nbformat_minor": 2
1 year ago
}