更新文档

main
wanggaofeng 9 months ago
parent 09eaa0336c
commit 4988cbecc6

@ -28,6 +28,12 @@
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
@ -43,6 +49,8 @@
"global using System.Text;\n",
"global using System.Linq;\n",
"global using System.IO;\n",
"global using System.Threading;\n",
"global using System.Threading.Tasks;\n",
"\n",
"global using HttpClientStudy.Core;\n",
"\n",
@ -50,9 +58,9 @@
"var global_queryPort = 80;\n",
"var global_queryBaseUrl = $\"http://{global_queryDomain}:{global_queryPort}\";\n",
"\n",
"var global_ips =Dns.GetHostAddresses(global_queryDomani);\n",
"var global_queryIp = ips.First().ToString();\n",
"var global_netstat_filter = $\"{queryIp}:{global_queryPort}\";"
"var global_ips = Dns.GetHostAddresses(global_queryDomain);\n",
"var global_queryIp = global_ips.First().ToString();\n",
"var global_netstat_filter = $\"{global_queryIp}:{global_queryPort}\";"
]
},
{
@ -66,6 +74,12 @@
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
@ -557,6 +571,12 @@
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
@ -597,6 +617,141 @@
"source": [
"## 3、推荐使用方式"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"总则:\n",
"\n",
" 一、 应使用长期客户端(静态对象、单例等),并设置 PooledConnectionLifetime。这能解决DNS问题和套接字耗尽问题。\n",
" \n",
" 二、 使用 IHttpClientFactory 创建的短期客户端:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"+ 在 .NET Core 和 .NET 5+ 中:\n",
" \n",
" + 根据预期的 DNS 更改,使用 static 或 singletonHttpClient 实例,并将 PooledConnectionLifetime 设置为所需间隔(例如 2 分钟)。 这可以解决端口耗尽和 DNS 更改两个问题,而且不会增加 IHttpClientFactory 的开销。 如果需要模拟处理程序,可以单独注册它。\n",
" \n",
" + 使用 IHttpClientFactory可以针对不同的用例使用多个以不同方式配置的客户端。 但请注意,工厂创建的客户端生存期较短,一旦创建客户端,工厂就不再可以控制它。\n",
" 工厂合并 HttpMessageHandler 实例,如果其生存期尚未过期,则当工厂创建新的 HttpClient 实例时,可以从池中重用处理程序。 这种重用避免了任何套接字耗尽问题。\n",
" 如果需要 IHttpClientFactory 提供的可配置性,我们建议使用类型化客户端方法。\n",
"\n",
"+ 在 .NET Framework 中,使用 IHttpClientFactory 管理 HttpClient 实例。 如果不使用工厂,而是改为自行为每个请求创建新的客户端实例,则可能耗尽可用的端口。 \n",
"\n",
"`提示`: 如果应用需要 Cookie请考虑禁用自动 Cookie 处理或避免使用 IHttpClientFactory。 共用 HttpMessageHandler 实例会导致共享 CookieContainer 对象。 意外的 CookieContainer 对象共享通常会导致错误的代码。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [],
"source": [
"{ //不推荐的示例\n",
" int requestCount =0;\n",
"\n",
" //这会建立10个 HttpClient \n",
" //尽管使用了Using不过Using只保证应用进程释放实例但是http请求是跨操作系统、跨网络的操作调用Using的进程管不了操作系统更管不了网络。\n",
" //如果把循环次数加大到 65535 就会一定导致夏套接字耗尽(2000以很可能就会出现)。\n",
" Parallel.For(0,10,async (a,b)=>\n",
" {\n",
" using (var client = new HttpClient())\n",
" {\n",
" _ = await client.GetAsync(global_queryBaseUrl);\n",
" } \n",
" Interlocked.Add(ref requestCount, 1);\n",
" });\n",
"}\n",
"\n",
"{ //使用长期客户端\n",
" using (var client = new HttpClient())\n",
" {\n",
" for(int i=0; i<10; i++)\n",
" {\n",
" //n次调用均使用同一个 HttpClient 实例\n",
" _ = await client.GetAsync(global_queryBaseUrl);\n",
" }\n",
" }// 所有调用完成,才释放 HttpClient 实例\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4、静态客户端的复原能力"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"ename": "Error",
"evalue": "Command cancelled.",
"output_type": "error",
"traceback": [
"Command cancelled."
]
}
],
"source": [
"#r \"nuget:Polly\"\n",
"#r \"nuget:Microsoft.Extensions.Http.Resilience\"\n",
"using System;\n",
"using System.Net.Http;\n",
"using Microsoft.Extensions.Http;\n",
"using Microsoft.Extensions.Http.Resilience;\n",
"using Polly;\n",
"\n",
"{\n",
" var retryPipeline = new ResiliencePipelineBuilder<HttpResponseMessage>()\n",
" .AddRetry(new HttpRetryStrategyOptions\n",
" {\n",
" BackoffType = DelayBackoffType.Exponential,\n",
" MaxRetryAttempts = 3\n",
" })\n",
" .Build();\n",
"\n",
" var socketHandler = new SocketsHttpHandler\n",
" {\n",
" PooledConnectionLifetime = TimeSpan.FromMinutes(15)\n",
" };\n",
"\n",
" #pragma warning disable EXTEXP0001\n",
" var resilienceHandler = new ResilienceHandler(retryPipeline)\n",
" {\n",
" InnerHandler = socketHandler,\n",
" };\n",
" #pragma warning restore EXTEXP0001\n",
"\n",
" var httpClient = new HttpClient(resilienceHandler);\n",
"\n",
" var response = await httpClient.GetAsync(\"https://www.baidu.com\");\n",
" var htmlText = await response.Content.ReadAsStringAsync();\n",
" Console.WriteLine($\"共有{htmlText.Length}个字符\");\n",
"}\n"
]
}
],
"metadata": {

Loading…
Cancel
Save