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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"source": [
"在 HttpClient 中使用 Cookie\n",
"============================="
]
},
{
"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 的有效期、路径等信息 | 调试和日志记录 |"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".NET (C#)",
"language": "C#",
"name": ".net-csharp"
},
"language_info": {
"name": "python"
},
"polyglot_notebook": {
"kernelInfo": {
"defaultKernelName": "csharp",
"items": [
{
"aliases": [],
"name": "csharp"
}
]
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}