更新笔记文档

main
bicijinlian 1 year ago
parent 589d37d7a9
commit 995a4a0648

@ -37,6 +37,15 @@
"![图](./Assets/概要图.svg) "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"HttpClient是应用程序进程中封装调用远程请求的类库。整个远程的执行是由进程向操作系统申请经由网卡、路由器等网络设备转换、传输到一台Web服务器然后返回的过程, HttpClient只是其中一个很小的环节。\n",
"\n",
"在这个基础上理解初代HttpClient问题(网络套接字用完 DNS问题等)、使用原则、请求管道、工厂模式、类型化客户端、Polly等项时会很轻松。比如即便使用Using包括了 HttpClient也会有套接字耗尽的问题是因为using只能释放进程中的对象但进程管理不了系统及网卡(这是在进程之上的),更不用说路由和互联网及被调用方的服务器了。"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -44,6 +53,28 @@
"## 前世今生"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### WebRequest\n",
"这是.NET创建者最初开发用于使用HTTP请求的标准类。\n",
"\n",
"使用HttpWebRequest可以让开发者控制请求/响应流程的各个方面,如 timeouts, cookies, headers, protocols。另一个好处是HttpWebRequest类不会阻塞UI线程。例如当您从响应很慢的API服务器下载大文件时您的应用程序的UI不会停止响应。\n",
"\n",
"HttpWebRequest通常和WebResponse一起使用一个发送请求一个获取数据。HttpWebRquest更为底层一些能够对整个访问过程有个直观的认识但同时也更加复杂一些。\n",
"\n",
"### WebClient\n",
"WebClient是一种更高级别的抽象是HttpWebRequest为了简化最常见任务而创建的使用过程中你会发现他缺少基本的headertimeoust的设置不过这些可以通过继承httpwebrequest来实现。使用WebClient可能比HttpWebRequest直接使用更慢大约几毫秒。但这种“低效率”带来了巨大的好处它需要更少的代码和隐藏了细节处理更容易使用并且在使用它时你不太可能犯错误。\n",
"\n",
"### HttpClient\n",
"HttpClient提供强大的功能并提供了异步支持可以轻松配合async await 实现异步请求等。\n",
"\n",
"随着更新发展,已经解决了前期问题(套接字耗尽、DNS、不灵活等),并发展了完整、完善的体系(基于Task的异步、连接池、类型化的客户端、工厂模式、Polly等)。\n",
"\n",
"是本项目的学习目标。"
]
},
{
"cell_type": "markdown",
"metadata": {
@ -58,14 +89,50 @@
}
},
"source": [
"## 架构图"
"## HttpClient架构图\n",
"\n",
"### .NetFramework 4及4.5 架构\n",
"HttpClient最初是作为NuGet包提供的该包可以选择包含在.NET Framework 4.0项目中。在.NET Framework 4.5中它作为BCL基本类库的一部分在框中提供。它建立在预先存在的HttpWebRequest实现之上。在.NET Framework中ServicePoint API可用于控制和管理HTTP连接包括通过为端点配置ConnectionLeaseTimeout来设置连接寿命。\n",
"\n",
"![.NetFramework](./Assets/架构.001.png)\n",
"\n",
"### .NET Core 1.0及1.1 架构\n",
".NET Core 1.0最初于2016年6月发布。与.NET Framework中可用的版本相比此第一个版本的API接口要小得多主要用于构建ASP.NET Core Web应用程序。由于.NET Core 1.0是HttpClient因此提供了API。但是不包括用于HttpWebRequest和ServicePoint的API。.NET Core 1.0中的HttpClient直接建立在使用非托管代码的OS平台API之上Windows API使用WinHTTPLinux和Mac使用LibCurl。\n",
"\n",
"值得注意的是到2016年8月很快就注意到重新使用HttpClient实例以防止套接字耗尽的建议有一个相当麻烦的副作用DNS\n",
"\n",
"![.NetFramework](./Assets/架构.002.png)\n",
"\n",
"### .NET Core 2.0 架构\n",
"在.NET Core 2.0中添加了HttpWebRequest以支持.NET Standard 2.0。它位于HttpClient实现的顶层这与.NET Framework 4.5+中的工作原理相反。还添加了ServicePoint尽管它的许多API接口要么要么会抛出未实现的异常要么根本就没有实现。\n",
"\n",
"![.NetFramework](./Assets/架构.003.png)\n",
"\n",
"### .NET CORE 2.1及后续 架构\n",
"这种有问题的行为导致团队不同团队进行了两项工作。\n",
"\n",
"ASP.NET团队开始研究**Microsoft.Extensions.Http包该包的主要功能是IHttpClientFactory**。这个针对HttpClient实例自用的工厂还包括基础HttpMessageHandler链的生命周期管理。如果您想了解有关此功能的更多信息可以查看我的系列博客文章我将在此介绍。\n",
"\n",
"IHttpClientFactory功能是作为ASP.NET Core 2.1的一部分发布的,对于许多人来说,这是一个很好的折衷方案,它解决了连接重用以及生命周期管理的问题。\n",
"\n",
"在同一时间范围内,.NET团队正在研究自己的解决方案。该团队也在.NET Core 2.1中发布在HttpClient的处理程序链的核心引入了一个新的**SocketsHttpHandler**。该处理程序直接建立在Socket API之上并在托管代码中实现HTTP。这项工作的一部分包括连接池系统以及为这些连接设置最大生存期的能力。\n",
"\n",
"![.NetFramework](./Assets/架构.003.png)\n",
"\n",
"说明:虽然默认情况下从.NET Core 2.1启用了SocketsHttpHandler但实现仅限于HTTP / 1.1通信。那些需要HTTP / 2的用户必须禁用该功能并使用较旧的处理程序链该处理程序链像以前一样依赖非托管代码并且不包括连接池。\n",
"\n",
"幸运的是,.NET Core 3.0中已消除了此限制并且现在提供了HTTP/2支持。这应该使用基于适合所有对象的SocketsHttpHandler链的HttpClient。\n",
"\n",
"结语:从.Net core 2.1开始,架构逐步稳定、完善。.Net 5、6、7、8中逐渐发展出一整套完整机制包括但不限于 连接池、工厂模式、Polly等。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 相关资源"
"## 后续\n",
"\n",
"后续将从基础使用到高级使用,一步步展开,一步步学习。"
]
},
{

@ -0,0 +1,420 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"source": [
"# HttpClient 使用准则\n",
"System.Net.Http.HttpClient 类用于发送 HTTP 请求以及从 URI 所标识的资源接收 HTTP 响应。 HttpClient 实例是应用于该实例执行的所有请求的设置集合,每个实例使用自身的连接池,该池将其请求与其他请求隔离开来。 \n",
"\n",
"从 .NET Core 2.1 开始SocketsHttpHandler 类提供实现,使行为在所有平台上保持一致。"
]
},
{
"cell_type": "markdown",
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"source": [
"## 1、DNS 行为\n",
"HttpClient 仅在创建连接时解析 DNS。它不跟踪 DNS 服务器指定的任何生存时间 (TTL)。 \n",
"\n",
"如果 DNS 条目定期更改(这可能在某些方案中发生),客户端将不会遵循这些更新。 要解决此问题,可以通过设置 PooledConnectionLifetime 属性来限制连接的生存期,以便在替换连接时重复执行 DNS 查找。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"using System.Net.Http;\n",
"\n",
"var handler = new SocketsHttpHandler\n",
"{\n",
" // Recreate every 15 minutes\n",
" PooledConnectionLifetime = TimeSpan.FromMinutes(15) \n",
"};\n",
"var sharedClient = new HttpClient(handler);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"上述 HttpClient 配置为重复使用连接 15 分钟。 PooledConnectionLifetime 指定的时间范围过后,系统会关闭连接,然后创建一个新连接。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2、共用连接(底层自动管理连接池)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"HttpClient 的连接池链接到其基础 SocketsHttpHandler。 \n",
"释放 HttpClient 实例时,它会释放池中的所有现有连接。 如果稍后向同一服务器发送请求,则必须重新创建一个新连接。 \n",
"因此,创建不必要的连接会导致性能损失。 \n",
"此外TCP 端口不会在连接关闭后立即释放。 (有关这一点的详细信息,请参阅 RFC 9293 中的 TCP TIME-WAIT。如果请求速率较高则可用端口的操作系统限制可能会耗尽。 \n",
"\n",
"为了避免端口耗尽问题,建议将 HttpClient 实例重用于尽可能多的 HTTP 请求。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 什么是连接池\n",
"SocketsHttpHandler为每个唯一端点建立连接池您的应用程序通过HttpClient向该唯一端点发出出站HTTP请求。在对端点的第一个请求上当不存在现有连接时将建立一个新的HTTP连接并将其用于该请求。该请求完成后连接将保持打开状态并返回到池中。\n",
"\n",
"对同一端点的后续请求将尝试从池中找到可用的连接。如果没有可用的连接,并且尚未达到该端点的连接限制,则将建立新的连接。达到连接限制后,请求将保留在队列中,直到连接可以自由发送它们为止。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 如何控制连接池"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"有三个主要设置可用于控制连接池的行为。\n",
"\n",
"+ PooledConnectionLifetime定义连接在池中保持活动状态的时间。此生存期到期后将不再为将来的请求而合并或发出连接。\n",
"\n",
"+ PooledConnectionIdleTimeout定义闲置连接在未使用时在池中保留的时间。一旦此生存期到期空闲连接将被清除并从池中删除。\n",
"\n",
"+ MaxConnectionsPerServer定义每个端点将建立的最大出站连接数。每个端点的连接分别池化。例如如果最大连接数为2则您的应用程序将请求发送到两个www.github.com和www.google.com总共可能最多有4个打开的连接。\n",
"\n",
"默认情况下,从.NET Core 2.1开始更高级别的HttpClientHandler将SocketsHttpHandler用作内部处理程序。没有任何自定义配置将应用连接池的默认设置。\n",
"\n",
"该**PooledConnectionLifetime默认是无限的因此虽然经常使用的请求连接可能会无限期地保持打开状态。该PooledConnectionIdleTimeout默认为2分钟如果在连接池中长时间未使用将被清理。MaxConnectionsPerServer**默认为int.MaxValue因此连接基本上不受限制。\n",
"\n",
"如果希望控制这些值中的任何一个则可以手动创建SocketsHttpHandler实例并根据需要进行配置。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"using System.Net.Http;\n",
"var socketsHandler = new SocketsHttpHandler\n",
"{\n",
"\tPooledConnectionLifetime = TimeSpan.FromMinutes(10),\n",
"\tPooledConnectionIdleTimeout = TimeSpan.FromMinutes(5),\n",
"\tMaxConnectionsPerServer = 10\n",
"};\n",
"\t\n",
"var client = new HttpClient(socketsHandler);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在前面的示例中对SocketsHttpHandler进行了配置以使连接将最多在10分钟后停止重新发出并关闭。如果闲置5分钟则连接将在池的清理过程中被更早地删除。我们还将最大连接数每个端点限制为十个。如果我们需要并行发出更多出站请求则某些请求可能会排队等待直到10个池中的连接可用为止。\n",
"要应用处理程序它将被传递到HttpClient的构造函数中。"
]
},
{
"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": [
"using System.Net;\n",
"using System.Net.Http;\n",
"\n",
"var ips = await Dns.GetHostAddressesAsync(\"www.hao123.com\");\n",
"string firstIp = ips.FirstOrDefault().ToString();\n",
"\t\n",
"foreach (var ipAddress in ips)\n",
"{\n",
" Console.WriteLine(ipAddress.MapToIPv4().ToString());\n",
"}\n",
"\n",
"//自定义行为\n",
"var socketsHandler = new SocketsHttpHandler\n",
"{\n",
" //连接池生命周期为10分钟连接在池中保持活动时间为10分钟\n",
" PooledConnectionLifetime = TimeSpan.FromMinutes(10),\n",
"\n",
" //池化链接的空闲超时时间为5分钟: 5分钟内连接不被重用则被释放后销毁\n",
" PooledConnectionIdleTimeout = TimeSpan.FromMinutes(5),\n",
" \n",
" //每端点的最大连接数设置为10个\n",
" MaxConnectionsPerServer = 10\n",
"};\n",
"\n",
"var client = new HttpClient(socketsHandler);\n",
"\n",
"for (var i = 0; i < 5; i++)\n",
"{\n",
" _ = await client.GetAsync(\"https://www.hao123.com\");\n",
" await Task.Delay(TimeSpan.FromSeconds(2));\n",
"}\n",
"\n",
"Console.WriteLine(\"请在程序退出后,执行下面命令行查看网络情况\");\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"使用我们刚刚讨论的设置此代码依次向同一端点发出5个请求。在每个请求之间它会暂停两秒钟。该代码还输出从DNS检索到的Google服务器的IPv4地址。我们可以使用此IP地址来查看通过PowerShell中发出的netstat命令对其打开的连接"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "pwsh"
},
"polyglot_notebook": {
"kernelName": "pwsh"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"#!set --value @csharp:firstIp --name queryIp\n",
"Write-Host \"请先执行上面的单元,再执行本单元\"\n",
"Write-Host \"异常话很可能是未查找IP为 $queryIp 的网络状\"\n",
"\n",
"netstat -ano | findstr $queryIp"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3、推荐使用方式"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "pwsh"
},
"polyglot_notebook": {
"kernelName": "pwsh"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"#!set --value @csharp:ips --name ips\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "pwsh"
},
"polyglot_notebook": {
"kernelName": "pwsh"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"#!set --value @csharp:ips --name ips\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"#!set --value @csharp:ips --name ips\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "pwsh"
},
"polyglot_notebook": {
"kernelName": "pwsh"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"#!set --value @csharp:firstIp --name firstIp\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "pwsh"
},
"polyglot_notebook": {
"kernelName": "pwsh"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"#!set --value @csharp:firstIp --name firstIp\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "javascript"
},
"polyglot_notebook": {
"kernelName": "javascript"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"#!set --value @csharp:firstIp --name firstIp\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "pwsh"
},
"polyglot_notebook": {
"kernelName": "pwsh"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"#!set --value @pwsh:$sss --name $sss\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
}

@ -0,0 +1,58 @@
{
"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、说明"
]
}
],
"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
}

@ -0,0 +1,63 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"source": [
"# 基础使用-发送请求"
]
},
{
"cell_type": "markdown",
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"source": [
"## 1、创建客户端"
]
},
{
"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
}

@ -0,0 +1,58 @@
{
"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、复用"
]
}
],
"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
}

@ -0,0 +1,58 @@
{
"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、复用"
]
}
],
"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
}

@ -0,0 +1,58 @@
{
"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、复用"
]
}
],
"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
}

@ -0,0 +1,58 @@
{
"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、复用"
]
}
],
"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
}

@ -0,0 +1,58 @@
{
"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、复用"
]
}
],
"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
}

@ -0,0 +1,58 @@
{
"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、复用"
]
}
],
"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
}

@ -0,0 +1,58 @@
{
"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、复用"
]
}
],
"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
}

@ -0,0 +1,58 @@
{
"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、复用"
]
}
],
"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
}

@ -0,0 +1,58 @@
{
"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、复用"
]
}
],
"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
}

@ -0,0 +1,58 @@
{
"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、复用"
]
}
],
"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
}

@ -0,0 +1,58 @@
{
"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、复用"
]
}
],
"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
}

@ -0,0 +1,58 @@
{
"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、复用"
]
}
],
"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
}

@ -0,0 +1,58 @@
{
"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、复用"
]
}
],
"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
}

@ -0,0 +1,69 @@
{
"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": {
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"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
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HttpClientStudy.Core.UseFactory
{
public class UseFactoryDemo
{
}
}

@ -16,7 +16,24 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{56D9132E-6D9B-4D4B-B82C-D8F74AA4373A}"
ProjectSection(SolutionItems) = preProject
Docs\1.1.概述.ipynb = Docs\1.1.概述.ipynb
Docs\1.2.使用原则.ipynb = Docs\1.2.使用原则.ipynb
Docs\1.2.使用准则.ipynb = Docs\1.2.使用准则.ipynb
Docs\1.3.0.基础使用.管理客户端.ipynb = Docs\1.3.0.基础使用.管理客户端.ipynb
Docs\1.3.1.基础使用.发送请求.ipynb = Docs\1.3.1.基础使用.发送请求.ipynb
Docs\1.3.2.基础使用.使用请求体.ipynb = Docs\1.3.2.基础使用.使用请求体.ipynb
Docs\1.3.3.基础使用.处理响应.ipynb = Docs\1.3.3.基础使用.处理响应.ipynb
Docs\1.3.4.基础使用.处理错误.ipynb = Docs\1.3.4.基础使用.处理错误.ipynb
Docs\1.3.5.基础使用.使用代理.ipynb = Docs\1.3.5.基础使用.使用代理.ipynb
Docs\1.3.6.基础使用.使用Json.ipynb = Docs\1.3.6.基础使用.使用Json.ipynb
Docs\1.3.7.基础使用.使用Cookie.ipynb = Docs\1.3.7.基础使用.使用Cookie.ipynb
Docs\1.4.0.高级使用.概述.ipynb = Docs\1.4.0.高级使用.概述.ipynb
Docs\1.4.1.高级使用.初始化.ipynb = Docs\1.4.1.高级使用.初始化.ipynb
Docs\1.4.2.高级使用.连接池.ipynb = Docs\1.4.2.高级使用.连接池.ipynb
Docs\1.4.3.高级使用.重复使用.ipynb = Docs\1.4.3.高级使用.重复使用.ipynb
Docs\1.4.4.高级使用.使用管道.ipynb = Docs\1.4.4.高级使用.使用管道.ipynb
Docs\1.4.5.高级使用.类型化客户端.ipynb = Docs\1.4.5.高级使用.类型化客户端.ipynb
Docs\1.4.6..高级使用.工厂模式.ipynb = Docs\1.4.6..高级使用.工厂模式.ipynb
Docs\1.4.7.高级使用.Polly.ipynb = Docs\1.4.7.高级使用.Polly.ipynb
Docs\1.5.总结.ipynb = Docs\1.5.总结.ipynb
Docs\说明.md = Docs\说明.md
EndProjectSection
EndProject

Loading…
Cancel
Save