<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>.Net &#8211; Bubblog</title>
	<atom:link href="https://blog.yangyuanping.com/tag/net/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.yangyuanping.com</link>
	<description>nullable reference types</description>
	<lastBuildDate>Tue, 23 Dec 2025 14:19:57 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>

<image>
	<url>https://blog.yangyuanping.com/wp-content/uploads/2025/11/cropped-patrick_log_logo_251121-2-32x32.png</url>
	<title>.Net &#8211; Bubblog</title>
	<link>https://blog.yangyuanping.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Mac 中使用 VSCode 开发 Framework 项目指南</title>
		<link>https://blog.yangyuanping.com/mac-%e4%b8%ad%e4%bd%bf%e7%94%a8-vscode-%e5%bc%80%e5%8f%91-framework-%e9%a1%b9%e7%9b%ae%e6%8c%87%e5%8d%97/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Tue, 23 Dec 2025 14:19:57 +0000</pubDate>
				<category><![CDATA[未分类]]></category>
		<category><![CDATA[.Net]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[VSCode]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1072</guid>

					<description><![CDATA[前置要求 对于 .NET Framework 4.5.2 项目，在 macOS 上需要使用 Mono 来运行。 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2>前置要求</h2>
<p>对于 .NET Framework 4.5.2 项目，在 macOS 上需要使用 Mono 来运行。</p>
<h2>第一步：安装必需工具</h2>
<h3>1. 安装 Mono</h3>
<pre><code class="language-bash">brew install mono</code></pre>
<p>验证安装：</p>
<pre><code class="language-bash">mono --version</code></pre>
<h3>2. 安装 NuGet</h3>
<pre><code class="language-bash">brew install nuget</code></pre>
<h3>3. 安装 MSBuild (包含在 Mono 中)</h3>
<p>验证安装：</p>
<pre><code class="language-bash">msbuild -version</code></pre>
<h3>4. 安装 XSP (Mono 的 Web 服务器)</h3>
<pre><code class="language-bash">brew install xsp</code></pre>
<h2>第二步：安装 VSCode 扩展</h2>
<p>在 VSCode 中安装以下扩展（已在 &lt;code&gt;.vscode/extensions.json&lt;/code&gt; 中推荐）：</p>
<ol>
<li><strong>C# Dev Kit</strong> &#8211; 微软官方 C# 支持</li>
<li><strong>C#</strong> &#8211; OmniSharp 语言服务</li>
<li><strong>.NET Test Explorer</strong> &#8211; 测试资源管理器</li>
</ol>
<p>重启 VSCode 以激活扩展。</p>
<h2>第三步：构建项目</h2>
<h3>方法 1：使用 VSCode 任务（推荐）</h3>
<ol>
<li>按 &lt;code&gt;Cmd+Shift+P&lt;/code&gt; 打开命令面板</li>
<li>选择 &lt;code&gt;Tasks: Run Task&lt;/code&gt;</li>
<li>选择 &lt;code&gt;构建解决方案 (Debug)&lt;/code&gt;</li>
</ol>
<h3>方法 2：使用终端命令</h3>
<pre><code class="language-bash"># 恢复 NuGet 包
nuget restore &lt;Solution-Name&gt;.sln

# 构建项目
msbuild &lt;Solution-Name&gt;.sln /p:Configuration=Debug</code></pre>
<h2>第四步：运行和调试</h2>
<h3>运行 WebAPI 项目</h3>
<h4>方法 1：使用 XSP（Mono Web 服务器）</h4>
<pre><code class="language-bash"># 在终端中运行
xsp4 --port=&lt;PORT&gt; --path=&lt;ProjectName&gt;</code></pre>
<p>然后访问：<a href="http://localhost:23985/api/message">http://localhost:23985/api/message</a></p>
<h4>方法 2：使用 VSCode 任务</h4>
<ol>
<li>按 &lt;code&gt;Cmd+Shift+P&lt;/code&gt;</li>
<li>选择 &lt;code&gt;Tasks: Run Task&lt;/code&gt;</li>
<li>选择 &lt;code&gt;运行 WebAPI (XSP)&lt;/code&gt;</li>
</ol>
<h3>调试代码</h3>
<ol>
<li>在代码中设置断点（点击行号左侧）</li>
<li>按 &lt;code&gt;F5&lt;/code&gt; 或点击调试面板的&quot;开始调试&quot;</li>
<li>选择配置：&lt;code&gt;调试 WebAPI (Mono)&lt;/code&gt;</li>
</ol>
<h3>运行单元测试</h3>
<h4>使用 VSCode 任务：</h4>
<ol>
<li>按 &lt;code&gt;Cmd+Shift+P&lt;/code&gt;</li>
<li>选择 &lt;code&gt;Tasks: Run Task&lt;/code&gt;</li>
<li>选择 &lt;code&gt;运行单元测试&lt;/code&gt;</li>
</ol>
<h4>使用命令行：</h4>
<pre><code class="language-bash"># 首先需要安装 NUnit Console Runner（如果还没有）
nuget install NUnit.ConsoleRunner -Version 3.15.0 -OutputDirectory packages

# 运行测试
mono packages/NUnit.ConsoleRunner.3.15.0/tools/nunit3-console.exe \
  &lt;TestProjectName&gt;/bin/Debug/&lt;TestProjectName&gt;.dll</code></pre>
<h2>常用 VSCode 快捷键</h2>
<ul>
<li>&lt;code&gt;Cmd+Shift+B&lt;/code&gt; &#8211; 运行默认构建任务</li>
<li>&lt;code&gt;F5&lt;/code&gt; &#8211; 开始调试</li>
<li>&lt;code&gt;Shift+F5&lt;/code&gt; &#8211; 停止调试</li>
<li>&lt;code&gt;F9&lt;/code&gt; &#8211; 切换断点</li>
<li>&lt;code&gt;F10&lt;/code&gt; &#8211; 单步跳过</li>
<li>&lt;code&gt;F11&lt;/code&gt; &#8211; 单步进入</li>
<li>&lt;code&gt;Cmd+K Cmd+D&lt;/code&gt; &#8211; 格式化文档</li>
</ul>
<h2>常见问题</h2>
<h3>1. Mono 找不到程序集</h3>
<p>确保已运行 &lt;code&gt;nuget restore&lt;/code&gt; 来恢复所有依赖包。</p>
<h3>2. MSBuild 失败</h3>
<p>检查 Mono 版本是否支持 .NET Framework 4.5.2：</p>
<pre><code class="language-bash">mono --version</code></pre>
<p>需要 Mono 5.0 或更高版本。</p>
<h3>3. XSP 无法启动</h3>
<p>确保端口 23985 未被占用：</p>
<pre><code class="language-bash">lsof -i :23985</code></pre>
<h3>4. OmniSharp 无法加载项目</h3>
<p>在 VSCode 设置中确保：</p>
<ul>
<li>&lt;code&gt;omnisharp.useModernNet&lt;/code&gt; 设置为 &lt;code&gt;false&lt;/code&gt;</li>
<li>&lt;code&gt;omnisharp.monoPath&lt;/code&gt; 指向正确的 Mono 安装路径</li>
</ul>
<h2>已知限制</h2>
<ol>
<li><strong>调试功能受限</strong>：Mono 的调试体验不如 Windows 上的 Visual Studio</li>
<li><strong>性能差异</strong>：Mono 运行性能可能低于 Windows .NET Framework</li>
<li><strong>某些 API 不可用</strong>：部分 Windows 特定的 API 在 Mono 上不支持</li>
</ol>
<h2>建议</h2>
<p>对于生产环境部署，建议：</p>
<ol>
<li>在 Windows Server 上使用 IIS 托管</li>
<li>或考虑将项目迁移到 .NET 6/8 以获得跨平台支持</li>
</ol>
<h2>迁移到现代 .NET 的好处</h2>
<p>如果你计划长期维护此项目，可以考虑迁移到 .NET 8：</p>
<ul>
<li>原生跨平台支持（无需 Mono）</li>
<li>更好的性能</li>
<li>现代化的工具链</li>
<li>长期支持（LTS）</li>
</ul>
<p>迁移步骤请参考：<a href="https://docs.microsoft.com/zh-cn/aspnet/core/migration/">https://docs.microsoft.com/zh-cn/aspnet/core/migration/</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>TencentOS Server 4 安装 dotnet 运行时</title>
		<link>https://blog.yangyuanping.com/tencentos-server-4-%e5%ae%89%e8%a3%85-dotnet-%e8%bf%90%e8%a1%8c%e6%97%b6/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Wed, 17 Dec 2025 18:39:49 +0000</pubDate>
				<category><![CDATA[Linux Nibbles]]></category>
		<category><![CDATA[.Net]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[TencentOS]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1051</guid>

					<description><![CDATA[TencentOS Server 4 基于 RHEL 8，使用 dnf： 添加 Microsoft 仓库 su [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>TencentOS Server 4 基于 RHEL 8，使用 dnf：</p>
<h1>添加 Microsoft 仓库</h1>
<p>sudo rpm -Uvh <a href="https://packages.microsoft.com/config/centos/8/packages-microsoft-prod.rpm">https://packages.microsoft.com/config/centos/8/packages-microsoft-prod.rpm</a></p>
<h1>安装运行时</h1>
<p>sudo dnf install -y aspnetcore-runtime-8.0</p>
<h1>验证</h1>
<p>dotnet &#8211;list-runtimes</p>
<p>如果上面的源不可用，可以用脚本安装：</p>
<h1>下载安装脚本</h1>
<p>curl -sSL <a href="https://dot.net/v1/dotnet-install.sh">https://dot.net/v1/dotnet-install.sh</a> -o dotnet-install.sh<br />
chmod +x dotnet-install.sh</p>
<h1>安装到 /usr/share/dotnet（全局）</h1>
<p>sudo ./dotnet-install.sh &#8211;channel 8.0 &#8211;runtime aspnetcore &#8211;install-dir /usr/share/dotnet</p>
<h1>创建软链接</h1>
<p>sudo ln -sf /usr/share/dotnet/dotnet /usr/bin/dotnet</p>
<h1>验证</h1>
<p>dotnet &#8211;list-runtimes</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Nginx + .NET 压测与连接问题排查总结</title>
		<link>https://blog.yangyuanping.com/nginx-net-%e5%8e%8b%e6%b5%8b%e4%b8%8e%e8%bf%9e%e6%8e%a5%e9%97%ae%e9%a2%98%e6%8e%92%e6%9f%a5%e6%80%bb%e7%bb%93/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Wed, 17 Dec 2025 16:41:10 +0000</pubDate>
				<category><![CDATA[Linux Nibbles]]></category>
		<category><![CDATA[.Net]]></category>
		<category><![CDATA[Server]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1049</guid>

					<description><![CDATA[Nginx + .NET 压测与连接问题排查总结 本文是一次完整的 线上问题排查 + 架构修复 + 压力测试验 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>Nginx + .NET 压测与连接问题排查总结</h1>
<blockquote>
<p>本文是一次完整的 <strong>线上问题排查 + 架构修复 + 压力测试验证</strong> 的工程级总结，可作为 <strong>事故复盘、容量评估报告、运维 Runbook</strong> 使用。</p>
</blockquote>
<hr />
<h2>一、问题背景与现象</h2>
<h3>初始问题</h3>
<ul>
<li>
<p>Nginx 错误日志频繁出现：</p>
<pre><code class="language-text">upstream timed out (110: Connection timed out) while connecting to upstream</code></pre>
</li>
<li>
<p>请求多为：</p>
<pre><code class="language-text">OPTIONS /api/Ads/resolve HTTP/2.0</code></pre>
</li>
<li>上游地址：&lt;code&gt;127.0.0.1:5085&lt;/code&gt;（.NET Kestrel）</li>
</ul>
<h3>同时观测到的内核异常</h3>
<ul>
<li>&lt;code&gt;listen queue overflow&lt;/code&gt;</li>
<li>&lt;code&gt;SYNs to LISTEN sockets dropped&lt;/code&gt;</li>
<li>&lt;code&gt;SYN cookies sent&lt;/code&gt;</li>
<li>&lt;code&gt;TCPTimeWaitOverflow&lt;/code&gt;</li>
</ul>
<h3>直接影响</h3>
<ul>
<li>Nginx 无法连接本机上游</li>
<li>API 出现大量失败</li>
<li>高并发下服务不可用</li>
</ul>
<hr />
<h2>二、根因分析（结论级）</h2>
<h3>1&#x20e3; Nginx → Kestrel 连接模型错误（<strong>核心根因</strong>）</h3>
<p>在 &lt;code&gt;location /&lt;/code&gt; 中错误地配置了：</p>
<pre><code class="language-nginx">proxy_set_header Connection "upgrade";</code></pre>
<p>导致：</p>
<ul>
<li>所有普通 HTTP 请求被迫使用 &lt;code&gt;Connection: upgrade&lt;/code&gt;</li>
<li>Keepalive 失效</li>
<li>每个请求都建立/断开 TCP 连接</li>
</ul>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png" alt="👉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>直接引发短连接风暴</strong></p>
<hr />
<h3>2&#x20e3; OPTIONS 预检请求被放大</h3>
<ul>
<li>外站（如豆瓣）触发大量跨域请求</li>
<li>每个请求都会先发 &lt;code&gt;OPTIONS&lt;/code&gt;</li>
<li>&lt;code&gt;OPTIONS&lt;/code&gt; 被转发到上游应用</li>
</ul>
<p>在短连接模型下形成 <strong>连接洪峰</strong>。</p>
<hr />
<h3>3&#x20e3; 内核层连锁反应</h3>
<ul>
<li>SYN backlog 被打满</li>
<li>accept queue 溢出</li>
<li>内核开始丢 SYN / 启用 SYN cookies</li>
<li>Nginx 连接上游直接超时（110）</li>
</ul>
<hr />
<h2>三、关键修复措施（工程级）</h2>
<h3>1&#x20e3; 引入 upstream keepalive（<strong>最关键修复</strong>）</h3>
<p>在 &lt;code&gt;http {}&lt;/code&gt; 作用域中新增：</p>
<pre><code class="language-nginx">upstream eaglex_upstream {
    server 127.0.0.1:5085;
    keepalive 256;
}</code></pre>
<p>统一使用：</p>
<pre><code class="language-nginx">proxy_pass http://eaglex_upstream;
proxy_http_version 1.1;
proxy_set_header Connection "";</code></pre>
<hr />
<h3>2&#x20e3; 修正 Connection 头使用方式（<strong>非常关键</strong>）</h3>
<ul>
<li>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 禁止在普通 HTTP 路径中使用：</p>
<pre><code class="language-nginx">Connection: upgrade</code></pre>
</li>
<li><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 只在 <strong>WebSocket 专用 location</strong> 中使用 upgrade</li>
</ul>
<hr />
<h3>3&#x20e3; 在 Nginx 层直接短路 OPTIONS 预检</h3>
<pre><code class="language-nginx">location = /api/Ads/resolve {
    if ($request_method = OPTIONS) {
        add_header Access-Control-Allow-Origin $http_origin always;
        add_header Access-Control-Allow-Methods "GET,POST,OPTIONS" always;
        add_header Access-Control-Allow-Headers "Content-Type,Authorization" always;
        add_header Access-Control-Max-Age 86400 always;
        return 204;
    }
    proxy_pass http://eaglex_upstream;
}</code></pre>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png" alt="👉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>彻底消除预检请求对上游的压力放大</strong></p>
<hr />
<h3>4&#x20e3; 缩短 proxy_connect_timeout（防止雪崩）</h3>
<pre><code class="language-nginx">proxy_connect_timeout 2s;</code></pre>
<p>避免 Nginx worker 在连接失败时长时间阻塞。</p>
<hr />
<h2>四、压测阶段的验证结论</h2>
<h3>压测过程中观测到的健康状态</h3>
<ul>
<li>&lt;code&gt;.NET&lt;/code&gt; CPU：≈ 260%–300%（4C 机器，尚有余量）</li>
<li>Nginx CPU：≈ 10%–20%</li>
<li>&lt;code&gt;ksoftirqd&lt;/code&gt;：极低</li>
<li>
<p>TCP 状态：</p>
<pre><code class="language-text">estab ≈ 3000
timewait ≈ 30
orphan = 0</code></pre>
</li>
<li>
<p>内核累计计数在压测前后 <strong>完全无增长</strong>：</p>
<ul>
<li>listen queue overflow</li>
<li>SYN dropped</li>
<li>TCPTimeWaitOverflow</li>
</ul>
</li>
</ul>
<h3>明确结论</h3>
<blockquote>
<p><strong>连接层 / Nginx / 内核 TCP 已完全稳定，系统瓶颈成功转移至 .NET 应用 CPU 层。</strong></p>
</blockquote>
<hr />
<h2>五、错误日志的两类问题区分（重要）</h2>
<h3>A. &lt;code&gt;110 Connection timed out&lt;/code&gt;</h3>
<pre><code class="language-text">while connecting to upstream</code></pre>
<ul>
<li>含义：连接队列 / accept / backlog 问题</li>
<li>根因：连接模型错误</li>
<li><strong>已在本次修复中解决</strong></li>
</ul>
<hr />
<h3>B. &lt;code&gt;111 Connection refused&lt;/code&gt;</h3>
<pre><code class="language-text">connect() failed (111: Connection refused)</code></pre>
<ul>
<li>含义：上游端口当时 <strong>没有进程在监听</strong></li>
<li>
<p>可能原因：</p>
<ul>
<li>dotnet 进程崩溃</li>
<li>被 OOM killer 杀死</li>
<li>重启 / 发布</li>
</ul>
</li>
</ul>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png" alt="👉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 属于 <strong>上游进程稳定性问题</strong>，与 backlog 无关。</p>
<hr />
<h2>六、压测与日常排障常用监控命令清单</h2>
<h3>1&#x20e3; TCP 全局状态（必看）</h3>
<pre><code class="language-bash">ss -s</code></pre>
<p>关注：&lt;code&gt;estab / timewait / orphan&lt;/code&gt;</p>
<hr />
<h3>2&#x20e3; 上游端口连接数（Nginx → Kestrel）</h3>
<pre><code class="language-bash">ss -ant | awk '$4=="127.0.0.1:5085"{c++} END{print c}'</code></pre>
<hr />
<h3>3&#x20e3; 上游连接状态分布</h3>
<pre><code class="language-bash">ss -ant | awk '$4=="127.0.0.1:5085"{print $1}' | sort | uniq -c | sort -nr</code></pre>
<hr />
<h3>4&#x20e3; 内核是否再次被打爆（差分判断）</h3>
<pre><code class="language-bash">netstat -s | egrep -i 'listen queue|SYNs to LISTEN|SYN cookies|TCPTimeWaitOverflow'</code></pre>
<blockquote>
<p>必须用 <strong>前后对比</strong> 判断是否仍在发生。</p>
</blockquote>
<hr />
<h3>5&#x20e3; Nginx 错误日志关键字</h3>
<pre><code class="language-bash">tail -n 200 /www/wwwlogs/eaglex_ads_api.error.log | egrep -i 'timed out|refused|502|504'</code></pre>
<hr />
<h3>6&#x20e3; 上游进程是否存活 / 是否重启</h3>
<pre><code class="language-bash">ps -p &lt;dotnet_pid&gt; -o pid,etimes,%cpu,%mem,cmd
ss -lntp | grep 5085</code></pre>
<hr />
<h3>7&#x20e3; OOM / 内核杀进程检查</h3>
<pre><code class="language-bash">dmesg -T | egrep -i 'oom|killed process'
journalctl -k | egrep -i 'oom|killed'</code></pre>
<hr />
<h3>8&#x20e3; .NET 运行时指标（强烈推荐）</h3>
<pre><code class="language-bash">dotnet-counters monitor System.Runtime --process-id &lt;pid&gt;</code></pre>
<p>关注：</p>
<ul>
<li>CPU Usage</li>
<li>ThreadPool Queue Length</li>
<li>% Time in GC</li>
</ul>
<hr />
<h2>七、最终工程级结论（可直接写入文档）</h2>
<blockquote>
<p>本次问题的根因是 Nginx → Kestrel 连接模型错误（短连接 + OPTIONS 预检放大），导致 TCP listen queue 溢出与 upstream connect timeout。</p>
<p>通过引入 upstream keepalive、修正 Connection 头、在 Nginx 层短路 CORS 预检，并配合合理的超时配置，连接层问题已完全消除。</p>
<p>压测结果表明：系统当前瓶颈已转移至 .NET 应用 CPU 层，TCP 与代理层稳定可靠，具备可预测的容量上限。</p>
</blockquote>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>UseHttpsRedirection 与 UseHsts 的区别 </title>
		<link>https://blog.yangyuanping.com/usehttpsredirection-%e4%b8%8e-usehsts-%e7%9a%84%e5%8c%ba%e5%88%ab/</link>
		
		<dc:creator><![CDATA[peny911]]></dc:creator>
		<pubDate>Mon, 24 Nov 2025 12:09:12 +0000</pubDate>
				<category><![CDATA[未分类]]></category>
		<category><![CDATA[.Net]]></category>
		<guid isPermaLink="false">https://blog.yangyuanping.com/?p=1029</guid>

					<description><![CDATA[两者都与 HTTPS 安全相关，但作用机制不同： app.UseHttpsRedirection() 作用：H [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>两者都与 HTTPS 安全相关，但作用机制不同：</p>
<p>app.UseHttpsRedirection()</p>
<p>作用：HTTP 到 HTTPS 的即时重定向</p>
<ul>
<li>
<p>当用户访问 <a href="http://example.com">http://example.com</a> 时</p>
</li>
<li>
<p>服务器返回 307/308 重定向响应</p>
</li>
<li>
<p>浏览器自动跳转到 <a href="https://example.com">https://example.com</a></p>
</li>
<li>
<p>每次 HTTP 请求都会重定向</p>
<p>特点：</p>
</li>
<li>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 立即生效，无需浏览器记忆</p>
</li>
<li>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 首次请求仍是 HTTP（可能被拦截）</p>
</li>
<li>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 每次都需要一次额外的重定向请求</p>
<p>响应示例：<br />
HTTP/1.1 308 Permanent Redirect<br />
Location: <a href="https://example.com">https://example.com</a></p>
<hr />
<p>app.UseHsts()</p>
<p>作用：HTTP 严格传输安全（HTTP Strict Transport Security）</p>
</li>
<li>
<p>首次访问（HTTPS）后，服务器返回特殊响应头</p>
</li>
<li>
<p>浏览器记住&quot;这个网站只能用 HTTPS&quot;</p>
</li>
<li>
<p>之后浏览器自动将所有 HTTP 请求改为 HTTPS</p>
</li>
<li>
<p>甚至在发送请求前就转换</p>
<p>特点：</p>
</li>
<li>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 浏览器端强制，无需服务器重定向</p>
</li>
<li>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 防止中间人攻击（用户无法绕过）</p>
</li>
<li>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 首次访问必须是 HTTPS 才能设置</p>
</li>
<li>
<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 设置后很难撤销（有过期时间）</p>
<p>响应头示例：<br />
Strict-Transport-Security: max-age=31536000; includeSubDomains</p>
<p>参数说明：</p>
</li>
<li>
<p>max-age=31536000：浏览器记住 1 年</p>
</li>
<li>
<p>includeSubDomains：所有子域名也强制 HTTPS</p>
<hr />
<p>对比总结</p>
<table>
<thead>
<tr>
<th>特性</th>
<th>UseHttpsRedirection</th>
<th>UseHsts</th>
</tr>
</thead>
<tbody>
<tr>
<td>工作位置</td>
<td>服务器端重定向</td>
<td>浏览器端强制</td>
</tr>
<tr>
<td>首次访问</td>
<td>HTTP 可访问（重定向）</td>
<td>必须 HTTPS</td>
</tr>
<tr>
<td>后续访问</td>
<td>每次都重定向</td>
<td>浏览器自动转 HTTPS</td>
</tr>
<tr>
<td>性能</td>
<td>多一次请求</td>
<td>无额外请求</td>
</tr>
<tr>
<td>安全性</td>
<td>中等（首次可被劫持）</td>
<td>高（浏览器强制）</td>
</tr>
<tr>
<td>撤销难度</td>
<td>随时可撤销</td>
<td>需等待过期（max-age）</td>
</tr>
</tbody>
</table>
</li>
</ul>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
