整理、更新

main
bicijinlian 2 months ago
parent 5c8fd4ad29
commit a2746bfaeb

@ -91,8 +91,7 @@
"+ [使用管道](./1.4.4.高级使用.使用管道.ipynb)\n",
"+ [类型化客户端](./1.4.5.高级使用.类型化客户端.ipynb)\n",
"+ [工厂模式](./1.4.6.高级使用.工厂模式.ipynb)\n",
"+ [Polly库](./1.4.7.高级使用.Polly.ipynb)\n",
"+ [线程限流](./1.4.8.高级使用.线程限流.ipynb)"
"+ [Polly库](./1.4.7.高级使用.Polly.ipynb)"
]
},
{

@ -11,7 +11,18 @@
}
},
"source": [
"# HttpClient 使用原则"
"# HttpClient 使用代理功能"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"实际开发中HttpClient 通过代理访问目标服务器是常见的需求。\n",
"\n",
"本文将全面介绍如何在 .NET 中配置 HttpClient 使用代理Proxy功能包括基础使用方式、代码示例、以及与依赖注入结合的最佳实践。\n",
"\n",
"> 注意:运行代码之前,先开启`Fiddler Classic`及其代理功能,充当代理服务器。"
]
},
{
@ -28,7 +39,560 @@
}
},
"source": [
"## 1、复用"
"## 初始化"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 开启`Fiddler Classic`及其代理功能,充当代理服务器"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![代理服务器](./Assets/HttpClient-代理服务器设置.jpg)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 导入初始终化笔记文件,并且执行一次"
]
},
{
"cell_type": "code",
"execution_count": 1,
"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\"\n",
"\n",
"//共享变量\n",
"var fiddlerProxyAddress = \"127.0.0.1:8888\";\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🧩 什么是代理?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"代理Proxy是一种中间服务器用于转发客户端请求到目标服务器。它常用于以下目的\n",
"\n",
"- 访问受限资源:企业内网中,通过代理服务器访问外部资源;\n",
"- 提高安全性和隐私保护:代理可隐藏真实 IP 地址,保护目标服务器的隐私和数据安全;\n",
"- 提高性能:代理可使用请求缓存和负载均衡等,减少目标服务器的压力,提高性能;\n",
"- 方便调试、测试\n",
" - 代理服务器可记录请求和响应信息,方便调试和测试;\n",
" - `Fiddler Classic`等软件,默认是抓不到 HttpClient 的请求的,需要将其设置为代理服务器,才能抓取到 HttpClient 的请求;\n",
"\n",
"在 .NET HttpClient 中,可以通过多种方式来设置代理服务器。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🛠️ 设置 HttpClient 代理"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### ✅ 基本方式使用(无用户名密码)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"响应状态OK\r\n"
]
}
],
"source": [
"{ \n",
" // 设置 SocketsHttpHandler 使用代理\n",
" var handler = new SocketsHttpHandler()\n",
" {\n",
" UseProxy = true,\n",
" Proxy = new WebProxy(fiddlerProxyAddress),\n",
" };\n",
"\n",
" // 创建 HttpClient并且请求\n",
" using (var client = new HttpClient(handler))\n",
" {\n",
" var response = await client.GetAsync(\"https://www.baidu.com\");\n",
" \n",
" Console.WriteLine($\"响应状态:{response.StatusCode}\");\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"执行上面的单元格应该在fiddler classic 中,抓到请求包:可以查看和管理详细信息.\n",
"![Fillder 抓包](./Assets/HttpClient-代理-抓包.jpg)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### ✅ 带用户名和密码的代理"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"响应状态OK\r\n"
]
}
],
"source": [
"{ \n",
" // 设置 SocketsHttpHandler 使用代理\n",
" var handler = new SocketsHttpHandler()\n",
" {\n",
" UseProxy = true,\n",
" Proxy = new WebProxy(fiddlerProxyAddress)\n",
" {\n",
" //正式项目:机密数据一定要脱敏处理或者使用环境变量、机密管理器等手段\n",
" //因为Fiddler代理服务器没有用户凭据要求所以此处随意填写的。需要的话真实填写正确的用户凭据。\n",
" Credentials = new NetworkCredential(\"username\", \"password\"),\n",
" },\n",
" };\n",
"\n",
" // 创建 HttpClient并且请求\n",
" using (var client = new HttpClient(handler))\n",
" {\n",
" var response = await client.GetAsync(\"https://www.baidu.com\");\n",
" Console.WriteLine($\"响应状态:{response.StatusCode}\");\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"source": [
"### 📦 在IoC和工厂中使用 Proxy [推荐方式]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在 ASP.NET Core 或基于 IServiceCollection 的项目中,可以通过 UseSocketsHttpHandler 扩展方法,统一管理代理服务器配置。\n",
"\n",
"还可以根据客户端的命名不同,进行不同的代理服务器配置!"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"正常请求,响应内容为: Pong\r\n"
]
}
],
"source": [
"//IoC或工厂中设置代理\n",
"{\n",
" //IoC\n",
" var services = new ServiceCollection();\n",
"\n",
" //默认命名客户端\n",
" services\n",
" .AddHttpClient<HttpClient>(string.Empty)\n",
" .ConfigureHttpClient(client => \n",
" {\n",
" client.BaseAddress = new Uri(webApiBaseUrl);\n",
" client.Timeout = TimeSpan.FromSeconds(10);\n",
" })\n",
"\n",
" //配置代理服务器\n",
" .UseSocketsHttpHandler(handlerBuilder =>\n",
" {\n",
" handlerBuilder.Configure((handler,s) => \n",
" {\n",
" handler.Proxy = new WebProxy(fiddlerProxyAddress);\n",
" }); \n",
" });\n",
"\n",
" //发送请求\n",
" var factory = services.BuildServiceProvider().GetRequiredService<IHttpClientFactory>();\n",
"\n",
" //正常请求\n",
" var defaultClient = factory.CreateClient();\n",
" var defaultContent = await defaultClient.GetStringAsync(\"api/hello/ping\");\n",
" Console.WriteLine($\"正常请求,响应内容为: {defaultContent}\");\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 🔄 动态切换代理服务器\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"要根据请求的不同(请求地址、请求方法、请求头、请求参数等)动态选择使用一同的代理服务器可以使用Pipeline中间件来管理。"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"LoggerDelegatingHandler -> SendAsync -> Before\n",
"ProxySelectorLastHandler -> SendAsync -> Before\n",
"ProxySelectorLastHandler -> SendAsync -> After\n",
"LoggerDelegatingHandler -> SendAsync -> After\n",
"OK\n",
"---------------------------------------------------\n",
"ProxySelectorLastHandler -> SendAsync -> Before\n",
"ProxySelectorLastHandler -> SendAsync -> After\n",
"OK\n"
]
}
],
"source": [
"///<summary>\n",
"/// 代理服务选择器中间件\n",
"/// 注意:此中间件会短路,必须设置为最后一个中间件\n",
"///</summary>\n",
"public class ProxySelectorLastHandler : DelegatingHandler\n",
"{\n",
" /// <summary>\n",
" /// 拦截请求,并动态设置代理\n",
" /// 注意:会短路其它中间件,要放最后\n",
" /// </summary>\n",
" protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken ct)\n",
" {\n",
" Console.WriteLine(\"ProxySelectorLastHandler -> SendAsync -> Before\");\n",
" //动态选择示例\n",
" var proxy = request.RequestUri.Host switch\n",
" {\n",
" string url when url.Contains(\"baidu\") => new WebProxy(\"127.0.0.1:8888\"),\n",
" string url when url.Contains(\"qq\") => new WebProxy(\"127.0.0.1:8888\"),\n",
" _ => null\n",
" };\n",
"\n",
" InnerHandler = new SocketsHttpHandler\n",
" {\n",
" Proxy = proxy,\n",
" UseProxy = proxy != null\n",
" };\n",
"\n",
"\n",
" //请求\n",
" HttpResponseMessage response = await base.SendAsync(request, ct);\n",
"\n",
" Console.WriteLine(\"ProxySelectorLastHandler -> SendAsync -> After\");\n",
"\n",
" return response;\n",
" }\n",
"}\n",
"\n",
"//日志中间件(管道类)\n",
"public class LoggerDelegatingHandler : DelegatingHandler\n",
"{\n",
" protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)\n",
" {\n",
" Console.WriteLine(\"LoggerDelegatingHandler -> Send -> Before\");\n",
"\n",
" HttpResponseMessage response = base.Send(request, cancellationToken);\n",
"\n",
" Console.WriteLine(\"LoggerDelegatingHandler -> Send -> After\");\n",
"\n",
" return response;\n",
" }\n",
"\n",
" protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\n",
" {\n",
" Console.WriteLine(\"LoggerDelegatingHandler -> SendAsync -> Before\");\n",
"\n",
" HttpResponseMessage response = await base.SendAsync(request, cancellationToken);\n",
"\n",
" Console.WriteLine(\"LoggerDelegatingHandler -> SendAsync -> After\");\n",
"\n",
" return response;\n",
" }\n",
"}\n",
"\n",
"//使用ProxySelectorLastHandler必须设置为最后一个中间件\n",
"{\n",
" var handlerLink = new LoggerDelegatingHandler()\n",
" {\n",
" InnerHandler = new ProxySelectorLastHandler(),\n",
" };\n",
"\n",
" var myClient = new HttpClient(handlerLink);\n",
" var response = await myClient.GetAsync(\"https://www.qq.com\");\n",
"\n",
" Console.WriteLine(response.StatusCode);\n",
" Console.WriteLine(\"---------------------------------------------------\");\n",
"}\n",
"\n",
"\n",
"// ProxySelectorLastHandler 不是最后一个的话,其它中间件无效(被短路)\n",
"{\n",
" var handlerLink = new ProxySelectorLastHandler()\n",
" {\n",
" InnerHandler = new LoggerDelegatingHandler (),\n",
" };\n",
"\n",
" var myClient = new HttpClient(handlerLink);\n",
" var response = await myClient.GetAsync(\"https://www.qq.com\");\n",
"\n",
" Console.WriteLine(response.StatusCode);\n",
"}\n",
"\n",
"//注意看输出:后面的没有日志中间件的任何输出"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🔐 HTTPS 代理信任问题"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"当使用 HTTPS 代理时,可能会遇到 SSL/TLS 证书不被信任的问题,尤其是在测试环境中使用自签名证书。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### ✅解决方法一:忽略证书验证(⚠️ 注意:仅用于开发环境)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"OK\r\n"
]
}
],
"source": [
"var handler = new HttpClientHandler\n",
"{\n",
" Proxy = new WebProxy(fiddlerProxyAddress),\n",
" UseProxy = true,\n",
" ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true\n",
"};\n",
"\n",
"using (var client = new HttpClient(handler))\n",
"{ \n",
" var response = await client.GetAsync(\"https://www.baidu.com\");\n",
" Console.WriteLine(response.StatusCode);\n",
"};\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### ✅ 解决方法二:手动添加根证书信任"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"OK\r\n"
]
}
],
"source": [
"using System.Security;\n",
"using System.Security.Cryptography;\n",
"using System.Security.Cryptography.X509Certificates;\n",
"\n",
"var file = Environment.CurrentDirectory + \"\\\\Assets\\\\FiddlerRoot.cer\";\n",
"//Console.WriteLine(file);\n",
"var rootCert = System.Security.Cryptography.X509Certificates.X509CertificateLoader.LoadCertificateFromFile(file);\n",
"\n",
"var handler = new HttpClientHandler\n",
"{\n",
" Proxy = new WebProxy(fiddlerProxyAddress),\n",
" UseProxy = true,\n",
" ServerCertificateCustomValidationCallback = (request, cert, chain, errors) =>\n",
" {\n",
" //return true;\n",
" return chain.ChainElements.Any(x => x.Certificate.Thumbprint == cert.Thumbprint); // 验证证书链包含指定根证书\n",
" }\n",
"};\n",
"\n",
"using (var client = new HttpClient(handler))\n",
"{ \n",
" var response = await client.GetAsync(\"https://www.baidu.com\");\n",
" Console.WriteLine(response.StatusCode);\n",
"};"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📌 总结"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"通过本文,你应该掌握了以下内容:\n",
"\n",
"+ 如何在 HttpClient 中直接设置代理\n",
"+ 如何在依赖注入系统中配置全局代理\n",
"+ 如何通过环境变量设置代理\n",
"+ 如何验证代理是否生效\n",
"+ 实际使用中的注意事项\n",
"+ 动态选择及证书信任"
]
}
],

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

@ -1,70 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"source": [
"# HttpClient 限流(System.Threading.RateLimiting)"
]
},
{
"cell_type": "markdown",
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"source": [
"## 1、System.Threading.RateLimiting 概述"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2、结合HttpClient 实现限流"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
}
],
"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
}

@ -1,78 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"source": [
"# HttpClient 总结"
]
},
{
"cell_type": "markdown",
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"source": [
"## 1、系统结束也是新的开始"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"#! csharp\n",
"Console.WriteLine(\"Hello World!\");"
]
}
],
"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
}

@ -1,222 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"source": [
"# HttpClient 测试"
]
},
{
"cell_type": "markdown",
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"source": [
"## 1、引用项目Dll"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"//引用项目\n",
"#r \"./Publish/HttpClientStudy.Core/HttpClientStudy.Core.dll\"\n",
"\n",
"//执行C#工具方法\n",
"using HttpClientStudy.Core.Utilities;\n",
"\n",
"\n",
"var result = AppUtility.RunCmd(\"ls\");\n",
"Console.WriteLine(result);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2、Powershell 管理项目"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"dotnet_interactive": {
"language": "pwsh"
},
"polyglot_notebook": {
"kernelName": "pwsh"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"#启动已发布的WebApi项目\n",
"Start-Process -FilePath dotnet -ArgumentList \".\\Publish\\HttpClientStudy.WebApp\\HttpClientStudy.WebApp.dll\""
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"dotnet_interactive": {
"language": "pwsh"
},
"polyglot_notebook": {
"kernelName": "pwsh"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"# 编译并启动WebApi项目\n",
"Start-Process -FilePath dotnet -ArgumentList \"run --project ..\\HttpClientStudy.WebApp\\HttpClientStudy.WebApp.csproj\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "pwsh"
},
"polyglot_notebook": {
"kernelName": "pwsh"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"# 关闭项目进程\n",
"$WebAppProcName =\"HttpClientStudy.WebApp\";\n",
"$WebAppProc = Get-Process $WebAppProcName -ErrorAction Ignore\n",
"if($null -eq $WebAppProc)\n",
"{\n",
" Write-Host \"进程没有找到,可能已经关闭\"\n",
"}\n",
"else {\n",
" $WebAppProc.Kill();\n",
" Write-Host \"$WebAppProcName 进程已退出\"\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3、C#类库管理项目"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"//启动已发布的WebApi项目\n",
"#r \"./Publish/HttpClientStudy.Core/HttpClientStudy.Core.dll\"\n",
"\n",
"{\n",
" var file = System.IO.Path.GetFullPath(\"./Publish/HttpClientStudy.WebApp/HttpClientStudy.WebApp.exe\",System.Environment.CurrentDirectory);\n",
"\n",
" file.Display();\n",
" var message = HttpClientStudy.Core.Utilities.AppUtility.RunWebApiExeFile(file);\n",
"\n",
" Console.WriteLine(message);\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"//关闭项目进程\n",
"#r \"./Publish/HttpClientStudy.Core/HttpClientStudy.Core.dll\"\n",
"\n",
"{\n",
" var message = HttpClientStudy.Core.Utilities.AppUtility.StopWebApiExeFile();\n",
" Console.WriteLine(message);\n",
"}"
]
}
],
"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
}

@ -1,125 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"source": [
"# 多语言笔记:内核中的各种路径"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"搞清楚,内核执行时的各种默认目录、路径,方便解决一些引用、文件等跟路径有关的问题。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"// C#中,内核执行时,各种默认路径如下:\n",
"\n",
"using System;\n",
"using System.IO;\n",
"using System.Threading;\n",
"using System.Threading.Tasks;\n",
"using System.Diagnostics;\n",
"using System.Reflection;\n",
"using Microsoft.Extensions.DependencyInjection;\n",
"\n",
" var pathDic = new Dictionary<string, (string desc, string? path)>() \n",
" {\n",
" //当前运行的exe的完整路径包含exe文件名只用于WinForm\n",
" {\"Application.ExecutablePath\",(\"程序集基完整路径(仅WinForm)\", \"Application.ExecutablePath 只适用于WinForm\") },\n",
"\n",
" //程序的启动路径只用于WinForm\n",
" {\"Application.StartupPath\",(\"程序集启动路径(仅WinForm)\", \"Application.StartupPath 只适用于WinForm\") },\n",
"\n",
" //当前执行的exe或启动项目的路径通过AppContext\n",
" {\"AppContext.BaseDirectory\",(\"执行或启动路径\",AppContext.BaseDirectory) }, \n",
"\n",
" //当前执行的exe的目录不包含exe名使用AppDomain\n",
" {\"AppDomain.CurrentDomain.BaseDirectory\",(\"程序集解析程序用于探测程序集的基目录\",AppDomain.CurrentDomain.BaseDirectory) }, \n",
"\n",
" //程序安装或启动基目录 包含应用程序的目录的名称\n",
" {\"AppDomain.CurrentDomain.SetupInformation.ApplicationBase\",(\"程序安装或启动基目录\",AppDomain.CurrentDomain.SetupInformation.ApplicationBase) }, \n",
"\n",
" //当前进程的主模块路径包含exe名\n",
" {\"Process.GetCurrentProcess().MainModule.FileName\",(\"当前进程的主模块路径\",Process.GetCurrentProcess()?.MainModule?.FileName) }, \n",
"\n",
" //环境变量:用户当前工作目录的完整限定路径\n",
" {\"Environment.CurrentDirectory\",(\"用户当前工作目录的完整限定路径\",Environment.CurrentDirectory) }, \n",
"\n",
" //环境变量当前exe的完整路径包含exe名通过命令行参数\n",
" {\"Environment.GetCommandLineArgs()[0]\",(\"当前exe的完整路径\",Environment.GetCommandLineArgs()[0]) }, \n",
"\n",
" //当前工作目录的路径(可变)\n",
" {\"Directory.GetCurrentDirectory\",(\"当前工作目录的路径(可变)\",Directory.GetCurrentDirectory()) },\n",
" \n",
" //当前Assembly的加载路径包含dll或exe名\n",
" {\"Assembly.GetExecutingAssembly().Location\",(\"当前Assembly的加载路径\",Assembly.GetExecutingAssembly().Location) },\n",
"\n",
" //入口程序集的路径\n",
" {\"Assembly.GetEntryAssembly().Location\",(\"入口程序集的路径\",Assembly.GetEntryAssembly()?.Location) },\n",
"\n",
" //已过时当前程序集的CodeBase路径可能为file URI格式\n",
" {\"Assembly.GetExecutingAssembly().CodeBase\",(\"当前程序集的CodeBase路径\",Assembly.GetExecutingAssembly()?.CodeBase) },\n",
"\n",
" //已过时入口程序集的CodeBase路径可能为file URI格式\n",
" {\"Assembly.GetEntryAssembly().CodeBase\",(\"入口程序集的CodeBase路径\",Assembly.GetEntryAssembly()?.CodeBase) },\n",
" };\n",
"\n",
" var message = string.Empty;\n",
" foreach (var item in pathDic)\n",
" {\n",
" message += $\"{item.Key} => {item.Value.path}{Environment.NewLine}\";\n",
" }\n",
"\n",
" Console.WriteLine(message);"
]
}
],
"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
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

@ -1,10 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using HttpClientStudy.WebApp.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
namespace HttpClientStudy.WebApp.Controllers
{
@ -21,7 +17,7 @@ namespace HttpClientStudy.WebApp.Controllers
/// 构造
/// </summary>
public AdvancedGetController(ILogger<AdvancedGetController> logger)
{
{
_logger = logger;
}
@ -33,7 +29,7 @@ namespace HttpClientStudy.WebApp.Controllers
public async Task<IActionResult> GetWithBody()
{
if (Request.Body == null)
{
{
return new JsonResult(BaseResultUtil.Fail("没有请求体"));
}
@ -58,7 +54,7 @@ namespace HttpClientStudy.WebApp.Controllers
/// 携带请求正文:使用模型绑定
/// </summary>
[HttpGet]
public async Task<IActionResult> GetWithFormBody([FromForm] int Id,[FromForm] string name)
public async Task<IActionResult> GetWithFormBody([FromForm] int Id, [FromForm] string name)
{
AdvancedGetModel vm = new AdvancedGetModel() { Id = Id, Name = name };
var result = BaseResultUtil.Success(vm);
@ -170,7 +166,7 @@ namespace HttpClientStudy.WebApp.Controllers
/// </summary>
/// <returns></returns>
[HttpPost]
public IActionResult PostFormData([FromForm,Required]int id, [FromForm,Required]string name)
public IActionResult PostFormData([FromForm, Required] int id, [FromForm, Required] string name)
{
var paras = $"{nameof(id)}={id}&{nameof(name)}={name}";
var result = BaseResultUtil.Success(paras);
@ -183,7 +179,7 @@ namespace HttpClientStudy.WebApp.Controllers
/// </summary>
/// <returns></returns>
[HttpPost]
public IActionResult PostJsonData([FromBody]AdvancedGetModel? vm)
public IActionResult PostJsonData([FromBody] AdvancedGetModel? vm)
{
var result = BaseResultUtil.Success(vm);
return Ok(result);

@ -1,10 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using HttpClientStudy.WebApp.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
namespace HttpClientStudy.WebApp.Controllers
{
@ -20,8 +16,8 @@ namespace HttpClientStudy.WebApp.Controllers
/// <summary>
/// 构造
/// </summary>
public AdvancedPostController(ILogger<AdvancedPostController> logger)
{
public AdvancedPostController(ILogger<AdvancedPostController> logger)
{
_logger = logger;
}
@ -39,18 +35,18 @@ namespace HttpClientStudy.WebApp.Controllers
{
string content = "请求体没有数据";
if (Request.ContentLength>0)
if (Request.ContentLength > 0)
{
byte[] bytes = new byte[(int)Request.ContentLength];
await Request.Body.ReadAsync(bytes);
await Request.Body.ReadAsync(bytes).ConfigureAwait(false);
content = UnicodeEncoding.UTF8.GetString(bytes);
}
var result = BaseResultUtil.Success(content);
return Ok(result);
}
}
/// <summary>
/// 接收请求体数据
@ -58,7 +54,7 @@ namespace HttpClientStudy.WebApp.Controllers
/// </summary>
/// <returns></returns>
[HttpPost]
public IActionResult FormData([FromForm,Required]int id, [FromForm,Required]string name)
public IActionResult FormData([FromForm, Required] int id, [FromForm, Required] string name)
{
var paras = $"{nameof(id)}={id}&{nameof(name)}={name}";
var result = BaseResultUtil.Success(paras);
@ -84,7 +80,7 @@ namespace HttpClientStudy.WebApp.Controllers
/// </summary>
/// <returns></returns>
[HttpPost]
public IActionResult JsonData([FromBody]AdvancedGetModel? vm)
public IActionResult JsonData([FromBody] AdvancedGetModel? vm)
{
var result = BaseResultUtil.Success(vm);
return Ok(result);

@ -0,0 +1,133 @@
using Microsoft.AspNetCore.Mvc;
namespace HttpClientStudy.WebApp.Controllers
{
/// <summary>
/// 普通(简单) 控制器
/// </summary>
[Route("api/[controller]/[action]")]
[ApiController]
public class CookieController : ControllerBase
{
private ILogger<CookieController> _logger;
private AccountService _accountService;
/// <summary>
/// 构造
/// </summary>
public CookieController(ILogger<CookieController> logger, AccountService accountService)
{
_logger = logger;
_accountService = accountService;
}
/// <summary>
/// 获取请求中的Cookie
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult GetRequestCookie()
{
var cookies = Request.Cookies;
if (cookies == null || cookies.Count == 0)
{
return Ok(BaseResultUtil.Success("", "没有Cookie"));
}
var result = BaseResultUtil.Success(cookies);
return Ok(result);
}
/// <summary>
/// 设置响应中的Cookie
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult GetResponseCookie()
{
//Cookie选项
var cookieOptions = new CookieOptions
{
// 设置过期时间如1天后过期
Expires = DateTimeOffset.Now.AddDays(1),
// 设置Cookie路径
Path = "/",
// 设置HttpOnly防止XSS攻击
HttpOnly = false,
// 设置Secure仅HTTPS传输
Secure = false,
// 设置SameSite策略
SameSite = SameSiteMode.Unspecified
};
var cookieData = new KeyValuePair<string, string>[]
{
new KeyValuePair<string, string>("ProjectName","WebApp"),
new KeyValuePair<string, string>("Version","Dotnet9"),
};
HttpContext.Response.Cookies.Append(cookieData, cookieOptions);
var result = BaseResultUtil.Success("响应头中已设置Cookie");
return Ok(result);
}
/// <summary>
/// 设置Cookie
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult SetResponseCookie(string cookieName, string cookieValue)
{
Response.Headers.TryAdd("Cookie", $"{cookieName}={cookieValue ?? string.Empty}");
var result = BaseResultUtil.Success($"响应头{cookieName}中已设置Cookie值{cookieValue}");
return Ok(result);
}
/// <summary>
/// 检测Cookie
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult CheckCookie(string? cookieName)
{
var cookies = Request.Cookies;
if (cookies == null || cookies.Count == 0)
{
return Ok(BaseResultUtil.Success("", "没有Cookie"));
}
if (string.IsNullOrWhiteSpace(cookieName))
{
var allCookie = BaseResultUtil.Success(cookies, "返回所有Cookie");
return Ok(allCookie);
}
KeyValuePair<string, string> findCookie = cookies.FirstOrDefault(c => c.Key == cookieName);
if (findCookie.Key == null)
{
return Ok(BaseResultUtil.Success($"请求头中没有找到名为{cookieName}的Cookie", $"没找到Cookie"));
}
else
{
return Ok(BaseResultUtil.Success($"请求头中名为{findCookie.Key}的Cookie,其值为{findCookie.Value}", $"找到Cookie"));
}
}
}
}
Loading…
Cancel
Save