<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://your-docusaurus-site.example.com/</id>
    <title>子虚伊人 Blog</title>
    <updated>2026-05-26T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://your-docusaurus-site.example.com/"/>
    <subtitle>子虚伊人 Blog</subtitle>
    <icon>https://your-docusaurus-site.example.com/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[从零搭建 Marzneshin + Nginx Proxy Manager + VLESS WS TLS 代理服务器]]></title>
        <id>https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide</id>
        <link href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide"/>
        <updated>2026-05-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[本文记录一套可以复刻的代理服务器搭建流程。最终效果是：]]></summary>
        <content type="html"><![CDATA[<p>本文记录一套可以复刻的代理服务器搭建流程。最终效果是：</p>
<ul>
<li class="">只暴露公网 <code>80</code> 和 <code>443</code>。</li>
<li class="">使用 Nginx Proxy Manager 统一管理 HTTPS、证书和反向代理。</li>
<li class="">Marzneshin 面板通过 <code>https://&lt;PROXY_DOMAIN&gt;/dashboard/</code> 访问。</li>
<li class="">代理节点使用 <code>VLESS + WebSocket + TLS</code>，客户端连接 <code>&lt;PROXY_DOMAIN&gt;:443</code>。</li>
<li class="">Xray 实际后端只监听 Docker 网关 <code>172.17.0.1:2087</code>，不直接暴露到公网。</li>
<li class="">Marzneshin 面板后端只监听 <code>172.17.0.1:8000</code>，不直接暴露到公网。</li>
<li class="">Clash Verge / Mihomo 订阅自带分流规则：国内直连，Google / Telegram / GFW / 非中国域名走代理。</li>
<li class="">规则文件通过自己的域名反代：<code>https://&lt;PROXY_DOMAIN&gt;/rules/google.txt</code>，客户端不直接访问 GitHub 或 jsDelivr。</li>
<li class="">修复部分 Clash 客户端订阅名显示成 <code>\"用户名\</code> 的问题。</li>
</ul>
<p>示例环境：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">系统：Ubuntu 22.04 LTS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">服务器公网 IP：&lt;SERVER_IP&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">域名：&lt;PROXY_DOMAIN&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">面板端口：172.17.0.1:8000</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Xray WS 后端端口：172.17.0.1:2087</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">WebSocket 路径：&lt;WS_PATH&gt;</span><br></span></code></pre></div></div>
<p>实际使用时，把 <code>&lt;PROXY_DOMAIN&gt;</code>、用户名、密码、服务器 IP 替换成你自己的值。不要把真实密码写进博客或公开仓库。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-dns-准备">1. DNS 准备<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#1-dns-%E5%87%86%E5%A4%87" class="hash-link" aria-label="1. DNS 准备的直接链接" title="1. DNS 准备的直接链接" translate="no">​</a></h2>
<p>先在你的 DNS 服务商处添加解析：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">类型：A</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">主机记录：clash</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">记录值：&lt;SERVER_IP&gt;</span><br></span></code></pre></div></div>
<p>等待生效后检查：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">dig</span><span class="token plain"> +short </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PROXY_DOMAIN</span><span class="token operator" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<p>应该返回你的服务器公网 IP。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-安装-docker-和-docker-compose">2. 安装 Docker 和 Docker Compose<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#2-%E5%AE%89%E8%A3%85-docker-%E5%92%8C-docker-compose" class="hash-link" aria-label="2. 安装 Docker 和 Docker Compose的直接链接" title="2. 安装 Docker 和 Docker Compose的直接链接" translate="no">​</a></h2>
<p>登录服务器：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">ssh</span><span class="token plain"> root@</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SERVER_IP</span><span class="token operator" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<p>安装 Docker 官方源：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">apt</span><span class="token plain"> update</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">apt</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-y</span><span class="token plain"> ca-certificates </span><span class="token function" style="color:#d73a49">curl</span><span class="token plain"> gnupg lsb-release</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-m</span><span class="token plain"> 0755 </span><span class="token parameter variable" style="color:#36acaa">-d</span><span class="token plain"> /etc/apt/keyrings</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">curl</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-fsSL</span><span class="token plain"> https://download.docker.com/linux/ubuntu/gpg </span><span class="token parameter variable" style="color:#36acaa">-o</span><span class="token plain"> /etc/apt/keyrings/docker.asc</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">chmod</span><span class="token plain"> a+r /etc/apt/keyrings/docker.asc</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin class-name">echo</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string" style="color:#e3116c">"deb [arch=</span><span class="token string variable" style="color:#36acaa">$(</span><span class="token string variable" style="color:#36acaa">dpkg --print-architecture</span><span class="token string variable" style="color:#36acaa">)</span><span class="token string" style="color:#e3116c"> signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">  </span><span class="token string variable" style="color:#36acaa">$(</span><span class="token string variable builtin class-name" style="color:#36acaa">.</span><span class="token string variable" style="color:#36acaa"> /etc/os-release </span><span class="token string variable operator" style="color:#393A34">&amp;&amp;</span><span class="token string variable" style="color:#36acaa"> </span><span class="token string variable builtin class-name" style="color:#36acaa">echo</span><span class="token string variable" style="color:#36acaa"> </span><span class="token string variable string" style="color:#e3116c">"</span><span class="token string variable string variable" style="color:#36acaa">${UBUNTU_CODENAME</span><span class="token string variable string variable operator" style="color:#393A34">:-</span><span class="token string variable string variable" style="color:#36acaa">$VERSION_CODENAME}</span><span class="token string variable string" style="color:#e3116c">"</span><span class="token string variable" style="color:#36acaa">)</span><span class="token string" style="color:#e3116c"> stable"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> /etc/apt/sources.list.d/docker.list</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">apt</span><span class="token plain"> update</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">apt</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-y</span><span class="token plain"> docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin</span><br></span></code></pre></div></div>
<p>验证：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--version</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> compose version</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> run </span><span class="token parameter variable" style="color:#36acaa">--rm</span><span class="token plain"> hello-world</span><br></span></code></pre></div></div>
<p>本文实测版本：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Docker version 29.5.2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Docker Compose version v5.1.4</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-安装-marzneshin">3. 安装 Marzneshin<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#3-%E5%AE%89%E8%A3%85-marzneshin" class="hash-link" aria-label="3. 安装 Marzneshin的直接链接" title="3. 安装 Marzneshin的直接链接" translate="no">​</a></h2>
<p>Marzneshin 官方基础安装命令：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">sudo</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">bash</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-c</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"</span><span class="token string variable" style="color:#36acaa">$(</span><span class="token string variable function" style="color:#d73a49">curl</span><span class="token string variable" style="color:#36acaa"> </span><span class="token string variable parameter variable" style="color:#36acaa">-sL</span><span class="token string variable" style="color:#36acaa"> https://github.com/marzneshin/Marzneshin/raw/master/script.sh</span><span class="token string variable" style="color:#36acaa">)</span><span class="token string" style="color:#e3116c">"</span><span class="token plain"> @ </span><span class="token function" style="color:#d73a49">install</span><br></span></code></pre></div></div>
<p>安装完成后创建管理员：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">marzneshin cli admin create </span><span class="token parameter variable" style="color:#36acaa">--sudo</span><br></span></code></pre></div></div>
<p>按提示输入管理员用户名和密码。示例：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">username: admin</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">password: &lt;ADMIN_PASSWORD&gt;</span><br></span></code></pre></div></div>
<p>安装后主要文件位置：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">/etc/opt/marzneshin/.env</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/etc/opt/marzneshin/docker-compose.yml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/var/lib/marzneshin/db.sqlite3</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/var/lib/marznode/xray_config.json</span><br></span></code></pre></div></div>
<p>初始状态下，面板通常可以通过：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">http://&lt;SERVER_IP&gt;:8000/dashboard/</span><br></span></code></pre></div></div>
<p>访问。后面我们会把它改成只监听 Docker 网关，由 NPM 统一暴露 HTTPS。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-安装-nginx-proxy-manager">4. 安装 Nginx Proxy Manager<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#4-%E5%AE%89%E8%A3%85-nginx-proxy-manager" class="hash-link" aria-label="4. 安装 Nginx Proxy Manager的直接链接" title="4. 安装 Nginx Proxy Manager的直接链接" translate="no">​</a></h2>
<p>创建目录：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">mkdir</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-p</span><span class="token plain"> /home/projects/nginx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin class-name">cd</span><span class="token plain"> /home/projects/nginx</span><br></span></code></pre></div></div>
<p>写入 <code>/home/projects/nginx/docker-compose.yml</code>：</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">services</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">npm</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"jc21/nginx-proxy-manager:latest"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">container_name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> nginx</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">proxy</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">manager</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">restart</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> always</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">ports</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"443:443"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"127.0.0.1:81:81"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"80:80"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">volumes</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> ./data</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">/data</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> ./letsencrypt</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">/etc/letsencrypt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">networks</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> web_proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">extra_hosts</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"host.docker.internal:host-gateway"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">networks</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">web_proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> web_proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">driver</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> bridge</span><br></span></code></pre></div></div>
<p>启动：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> compose up </span><span class="token parameter variable" style="color:#36acaa">-d</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ps</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--filter</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">nginx-proxy-manager</span><br></span></code></pre></div></div>
<p>这里把 NPM 管理后台端口绑定到 <code>127.0.0.1:81</code>，公网不能直接访问，更安全。需要登录 NPM 管理后台时，在本地电脑开 SSH 隧道：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">ssh</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-L</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">8181</span><span class="token plain">:127.0.0.1:81 root@</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SERVER_IP</span><span class="token operator" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<p>然后浏览器打开：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">http://127.0.0.1:8181</span><br></span></code></pre></div></div>
<p>首次登录后立刻修改 NPM 默认账号密码。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-让-marzneshin-面板只监听-docker-网关">5. 让 Marzneshin 面板只监听 Docker 网关<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#5-%E8%AE%A9-marzneshin-%E9%9D%A2%E6%9D%BF%E5%8F%AA%E7%9B%91%E5%90%AC-docker-%E7%BD%91%E5%85%B3" class="hash-link" aria-label="5. 让 Marzneshin 面板只监听 Docker 网关的直接链接" title="5. 让 Marzneshin 面板只监听 Docker 网关的直接链接" translate="no">​</a></h2>
<p>编辑：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">nano</span><span class="token plain"> /etc/opt/marzneshin/.env</span><br></span></code></pre></div></div>
<p>设置：</p>
<div class="language-dotenv codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dotenv codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">UVICORN_HOST="172.17.0.1"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">UVICORN_PORT=8000</span><br></span></code></pre></div></div>
<p>重启 Marzneshin：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token builtin class-name">cd</span><span class="token plain"> /etc/opt/marzneshin</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> compose up </span><span class="token parameter variable" style="color:#36acaa">-d</span><br></span></code></pre></div></div>
<p>检查监听：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ss </span><span class="token parameter variable" style="color:#36acaa">-tulpen</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">grep</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-E</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'(:8000|:80|:443)'</span><br></span></code></pre></div></div>
<p>理想结果：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">0.0.0.0:80      -&gt; NPM</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">0.0.0.0:443     -&gt; NPM</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">172.17.0.1:8000 -&gt; Marzneshin 面板</span><br></span></code></pre></div></div>
<p>此时公网 <code>http://&lt;SERVER_IP&gt;:8000</code> 应该访问不到，这是安全设计。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-在-npm-中创建-marzneshin-面板代理">6. 在 NPM 中创建 Marzneshin 面板代理<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#6-%E5%9C%A8-npm-%E4%B8%AD%E5%88%9B%E5%BB%BA-marzneshin-%E9%9D%A2%E6%9D%BF%E4%BB%A3%E7%90%86" class="hash-link" aria-label="6. 在 NPM 中创建 Marzneshin 面板代理的直接链接" title="6. 在 NPM 中创建 Marzneshin 面板代理的直接链接" translate="no">​</a></h2>
<p>进入 NPM 后创建 Proxy Host。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="details">Details<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#details" class="hash-link" aria-label="Details的直接链接" title="Details的直接链接" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Domain Names: &lt;PROXY_DOMAIN&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Scheme: http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Forward Hostname / IP: 172.17.0.1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Forward Port: 8000</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Cache Assets: 可开启</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Block Common Exploits: 开启</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Websockets Support: 开启</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="ssl">SSL<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#ssl" class="hash-link" aria-label="SSL的直接链接" title="SSL的直接链接" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Request a new SSL Certificate: 开启</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Force SSL: 开启</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">HTTP/2 Support: 可按需开启</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Email: 你的邮箱</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">I Agree: 勾选</span><br></span></code></pre></div></div>
<p>保存后访问：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">https://&lt;PROXY_DOMAIN&gt;/dashboard/</span><br></span></code></pre></div></div>
<p>如果能看到登录页，面板反代完成。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-创建-vless-websocket-入站">7. 创建 VLESS WebSocket 入站<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#7-%E5%88%9B%E5%BB%BA-vless-websocket-%E5%85%A5%E7%AB%99" class="hash-link" aria-label="7. 创建 VLESS WebSocket 入站的直接链接" title="7. 创建 VLESS WebSocket 入站的直接链接" translate="no">​</a></h2>
<p>进入 Marzneshin 面板，创建一个入站。核心目标是：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">协议：vless</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">传输：ws</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">监听地址：172.17.0.1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">监听端口：2087</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">WebSocket Path：&lt;WS_PATH&gt;</span><br></span></code></pre></div></div>
<p>注意：这里的 Xray 后端不需要自己处理 TLS。TLS 由 NPM 在 <code>443</code> 端口终止，NPM 再把 WebSocket 请求转发到 <code>172.17.0.1:2087</code>。</p>
<p>推荐入站概念配置：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Tag / Name: vless WS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Protocol: vless</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Network: ws</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Listen: 172.17.0.1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Port: 2087</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Path: &lt;WS_PATH&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">TLS: none / disabled</span><br></span></code></pre></div></div>
<p>再创建 Host，告诉客户端应该怎么连：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Address: &lt;PROXY_DOMAIN&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Port: 443</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Protocol: vless</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Network: ws</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Path: &lt;WS_PATH&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Security: tls</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">SNI: &lt;PROXY_DOMAIN&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Host: &lt;PROXY_DOMAIN&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Fingerprint: chrome</span><br></span></code></pre></div></div>
<p>保存后检查监听：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ss </span><span class="token parameter variable" style="color:#36acaa">-tulpen</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">grep</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2087</span><br></span></code></pre></div></div>
<p>理想结果：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">172.17.0.1:2087 -&gt; xray</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="8-在-npm-中添加-websocket-转发路径">8. 在 NPM 中添加 WebSocket 转发路径<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#8-%E5%9C%A8-npm-%E4%B8%AD%E6%B7%BB%E5%8A%A0-websocket-%E8%BD%AC%E5%8F%91%E8%B7%AF%E5%BE%84" class="hash-link" aria-label="8. 在 NPM 中添加 WebSocket 转发路径的直接链接" title="8. 在 NPM 中添加 WebSocket 转发路径的直接链接" translate="no">​</a></h2>
<p>编辑 <code>&lt;PROXY_DOMAIN&gt;</code> 这个 Proxy Host，添加 Custom Location：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Location: &lt;WS_PATH&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Scheme: http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Forward Hostname / IP: 172.17.0.1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Forward Port: 2087</span><br></span></code></pre></div></div>
<p>在这个 location 的高级配置里加入：</p>
<div class="language-nginx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-nginx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">proxy_set_header Host $host;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">proxy_set_header X-Forwarded-Scheme $scheme;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">proxy_set_header X-Forwarded-Proto  $scheme;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">proxy_set_header X-Forwarded-For    $remote_addr;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">proxy_set_header X-Real-IP          $remote_addr;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">proxy_set_header Upgrade $http_upgrade;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">proxy_set_header Connection $http_connection;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">proxy_http_version 1.1;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">proxy_read_timeout 3600s;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">proxy_send_timeout 3600s;</span><br></span></code></pre></div></div>
<p>保存后，NPM 生成的效果大致类似：</p>
<div class="language-nginx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-nginx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">location &lt;WS_PATH&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header Host $host;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header X-Forwarded-Scheme $scheme;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header X-Forwarded-Proto  $scheme;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header X-Forwarded-For    $remote_addr;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header X-Real-IP          $remote_addr;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header Upgrade $http_upgrade;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header Connection $http_connection;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_http_version 1.1;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_read_timeout 3600s;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_send_timeout 3600s;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_pass http://172.17.0.1:2087;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="9-创建服务和用户">9. 创建服务和用户<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#9-%E5%88%9B%E5%BB%BA%E6%9C%8D%E5%8A%A1%E5%92%8C%E7%94%A8%E6%88%B7" class="hash-link" aria-label="9. 创建服务和用户的直接链接" title="9. 创建服务和用户的直接链接" translate="no">​</a></h2>
<p>在 Marzneshin 中：</p>
<ol>
<li class="">创建 Service，例如 <code>&lt;SERVICE_NAME&gt;</code>。</li>
<li class="">勾选刚才创建的 <code>vless WS</code> 入站。</li>
<li class="">创建用户，例如 <code>&lt;USERNAME&gt;</code>。</li>
<li class="">让用户绑定到 <code>&lt;SERVICE_NAME&gt;</code> 服务。</li>
</ol>
<p>用户订阅链接形如：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">https://&lt;PROXY_DOMAIN&gt;/sub/&lt;USERNAME&gt;/&lt;USER_KEY&gt;</span><br></span></code></pre></div></div>
<p>不要公开 <code>&lt;USER_KEY&gt;</code>。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="10-让-clash--mihomo-订阅自带分流规则">10. 让 Clash / Mihomo 订阅自带分流规则<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#10-%E8%AE%A9-clash--mihomo-%E8%AE%A2%E9%98%85%E8%87%AA%E5%B8%A6%E5%88%86%E6%B5%81%E8%A7%84%E5%88%99" class="hash-link" aria-label="10. 让 Clash / Mihomo 订阅自带分流规则的直接链接" title="10. 让 Clash / Mihomo 订阅自带分流规则的直接链接" translate="no">​</a></h2>
<p>Marzneshin 支持自定义 Clash 模板，但当前版本底层的 <code>v2share</code> 会在渲染时把模板里的 <code>rules</code> 清空。所以需要一个很小的 Python 补丁，让模板里的规则能够保留下来，同时把 Marzneshin 生成的节点填入代理组。</p>
<p>创建目录：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">mkdir</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-p</span><span class="token plain"> /var/lib/marzneshin/templates</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">mkdir</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-p</span><span class="token plain"> /var/lib/marzneshin/patches</span><br></span></code></pre></div></div>
<p>写入 <code>/var/lib/marzneshin/patches/sitecustomize.py</code>：</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> random</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> v2share</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">clash </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> ClashConfig</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">PROXY_MARKER </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"__MARZNESHIN_PROXIES__"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">_ordered_configs</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">configs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sort</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> shuffle</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">False</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> shuffle</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> random</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sample</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">configs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">len</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">configs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> sort</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token builtin">sorted</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">configs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> key</span><span class="token operator" style="color:#393A34">=</span><span class="token keyword" style="color:#00009f">lambda</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">weight</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> configs</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">_expand_group_proxies</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">group</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> remarks</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxies </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> group</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"proxies"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> proxies </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> PROXY_MARKER</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        group</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"proxies"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> remarks</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">True</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">not</span><span class="token plain"> </span><span class="token builtin">isinstance</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">proxies</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">list</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">False</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expanded </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    found </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">False</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> proxy </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> proxies</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> proxy </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> PROXY_MARKER</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            expanded</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">extend</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">remarks</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            found </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">True</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">else</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            expanded</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">proxy</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> found</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        group</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"proxies"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> expanded</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> found</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">render_with_template_rules</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sort</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> shuffle</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">False</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    configs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> _ordered_configs</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_configs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sort</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">sort</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> shuffle</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">shuffle</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxies</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> remarks </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> proxy </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> configs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        proxies</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">_get_node</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">proxy</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        remarks</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">proxy</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">remark</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> yaml</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">safe_load</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">template_data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">or</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    result</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"proxies"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> proxies</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    result</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">setdefault</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"rules"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    groups </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"proxy-groups"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">or</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    marker_found </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">False</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> group </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> groups</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        marker_found </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> _expand_group_proxies</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">group</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> remarks</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">or</span><span class="token plain"> marker_found</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> groups </span><span class="token keyword" style="color:#00009f">and</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">not</span><span class="token plain"> marker_found</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        groups</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"proxies"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> remarks</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> yaml</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">safe_dump</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sort_keys</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">False</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> allow_unicode</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ClashConfig</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">render </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> render_with_template_rules</span><br></span></code></pre></div></div>
<p>写入 <code>/var/lib/marzneshin/templates/clash.yml</code>。下面的模板使用自己的域名反代规则文件：</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">mixed-port</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">7890</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">allow-lan</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">mode</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> rule</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">log-level</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> info</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">ipv6</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">unified-delay</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">tcp-concurrent</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">profile</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">store-selected</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">store-fake-ip</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">proxy-groups</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Automatic</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> url</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//www.gstatic.com/generate_204</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">300</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">tolerance</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">lazy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">proxies</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> __MARZNESHIN_PROXIES__</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> select</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">proxies</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> Automatic</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> __MARZNESHIN_PROXIES__</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">rule-providers</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">reject</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">behavior</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> domain</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">format</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//&lt;PROXY_DOMAIN</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain">/rules/reject.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ./ruleset/reject.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">86400</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">private</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">behavior</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> domain</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">format</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//&lt;PROXY_DOMAIN</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain">/rules/private.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ./ruleset/private.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">86400</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">icloud</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">behavior</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> domain</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">format</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//&lt;PROXY_DOMAIN</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain">/rules/icloud.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ./ruleset/icloud.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">86400</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">apple</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">behavior</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> domain</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">format</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//&lt;PROXY_DOMAIN</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain">/rules/apple.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ./ruleset/apple.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">86400</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">google</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">behavior</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> domain</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">format</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//&lt;PROXY_DOMAIN</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain">/rules/google.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ./ruleset/google.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">86400</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">behavior</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> domain</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">format</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//&lt;PROXY_DOMAIN</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain">/rules/proxy.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ./ruleset/proxy.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">86400</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">direct</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">behavior</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> domain</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">format</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//&lt;PROXY_DOMAIN</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain">/rules/direct.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ./ruleset/direct.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">86400</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">gfw</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">behavior</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> domain</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">format</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//&lt;PROXY_DOMAIN</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain">/rules/gfw.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ./ruleset/gfw.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">86400</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">tld-not-cn</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">behavior</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> domain</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">format</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//&lt;PROXY_DOMAIN</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain">/rules/tld</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">not</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">cn.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ./ruleset/tld</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">not</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">cn.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">86400</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">lancidr</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">behavior</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ipcidr</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">format</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//&lt;PROXY_DOMAIN</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain">/rules/lancidr.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ./ruleset/lancidr.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">86400</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">cncidr</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">behavior</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ipcidr</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">format</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//&lt;PROXY_DOMAIN</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain">/rules/cncidr.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ./ruleset/cncidr.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">86400</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">telegramcidr</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">behavior</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ipcidr</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">format</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//&lt;PROXY_DOMAIN</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain">/rules/telegramcidr.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ./ruleset/telegramcidr.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">86400</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">rules</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RULE</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SET</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">private</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RULE</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SET</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">lancidr</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">DIRECT</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">no</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">resolve</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RULE</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SET</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">reject</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">REJECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> DOMAIN</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SUFFIX</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">openai.com</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> DOMAIN</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SUFFIX</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">chatgpt.com</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> DOMAIN</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SUFFIX</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">oaistatic.com</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> DOMAIN</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SUFFIX</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">oaiusercontent.com</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> DOMAIN</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SUFFIX</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">anthropic.com</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> DOMAIN</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SUFFIX</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">claude.ai</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RULE</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SET</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">telegramcidr</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Proxy</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">no</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">resolve</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RULE</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SET</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">google</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RULE</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SET</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">gfw</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RULE</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SET</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">proxy</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RULE</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SET</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">icloud</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RULE</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SET</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">apple</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RULE</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SET</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">direct</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> GEOSITE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">cn</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> GEOIP</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">CN</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">DIRECT</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">no</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">resolve</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RULE</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SET</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">cncidr</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">DIRECT</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">no</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">resolve</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RULE</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">SET</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">tld</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">not</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">cn</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> MATCH</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Proxy</span><br></span></code></pre></div></div>
<p>启用模板和补丁。编辑 <code>/etc/opt/marzneshin/.env</code>，追加：</p>
<div class="language-dotenv codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dotenv codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">CUSTOM_TEMPLATES_DIRECTORY="/var/lib/marzneshin/templates/"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CLASH_SUBSCRIPTION_TEMPLATE="/var/lib/marzneshin/templates/clash.yml"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">PYTHONPATH="/var/lib/marzneshin/patches"</span><br></span></code></pre></div></div>
<p>重启：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token builtin class-name">cd</span><span class="token plain"> /etc/opt/marzneshin</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> compose up </span><span class="token parameter variable" style="color:#36acaa">-d</span><span class="token plain"> marzneshin</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="11-修正-clash-verge--mihomo-的订阅识别规则">11. 修正 Clash Verge / Mihomo 的订阅识别规则<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#11-%E4%BF%AE%E6%AD%A3-clash-verge--mihomo-%E7%9A%84%E8%AE%A2%E9%98%85%E8%AF%86%E5%88%AB%E8%A7%84%E5%88%99" class="hash-link" aria-label="11. 修正 Clash Verge / Mihomo 的订阅识别规则的直接链接" title="11. 修正 Clash Verge / Mihomo 的订阅识别规则的直接链接" translate="no">​</a></h2>
<p>有些客户端的 User-Agent 是 <code>Clash-Verge/2.0</code>，原默认规则可能因为大小写或写法没有命中 <code>clash-meta</code>，导致回落到 classic Clash。classic Clash 不支持 VLESS，订阅里会出现 <code>proxies: []</code>。</p>
<p>可以在 Marzneshin 面板的订阅设置里把规则调整成：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">(?i)^(clash[ .-]?verge|clash[ .-]?meta|mihomo) -&gt; clash-meta</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">(?i)^(clash|stash)                             -&gt; clash</span><br></span></code></pre></div></div>
<p>如果直接用命令修改 SQLite 中的订阅设置，可以执行：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> </span><span class="token builtin class-name">exec</span><span class="token plain"> marzneshin-marzneshin-1 </span><span class="token function" style="color:#d73a49">sh</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-lc</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'python - &lt;&lt; "PY"</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">from copy import deepcopy</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">from sqlalchemy.orm.attributes import flag_modified</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">from app.db import SessionLocal</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">from app.db.models import Settings</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">session = SessionLocal()</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">settings = session.query(Settings).first()</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">subscription = deepcopy(settings.subscription)</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">rules = subscription.get("rules", [])</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">new_rules = []</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">inserted_meta = False</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">inserted_clash = False</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">for rule in rules:</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">    result = rule.get("result", "")</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">    if result == "clash-meta" and not inserted_meta:</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">        new_rules.append({"pattern": "(?i)^(clash[ .-]?verge|clash[ .-]?meta|mihomo)", "result": "clash-meta"})</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">        inserted_meta = True</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">        continue</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">    if result == "clash" and not inserted_clash:</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">        new_rules.append({"pattern": "(?i)^(clash|stash)", "result": "clash"})</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">        inserted_clash = True</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">        continue</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">    new_rules.append(rule)</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">if not inserted_meta:</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">    new_rules.insert(0, {"pattern": "(?i)^(clash[ .-]?verge|clash[ .-]?meta|mihomo)", "result": "clash-meta"})</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">if not inserted_clash:</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">    new_rules.insert(1, {"pattern": "(?i)^(clash|stash)", "result": "clash"})</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">subscription["rules"] = new_rules</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">settings.subscription = subscription</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">flag_modified(settings, "subscription")</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">session.commit()</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">print(subscription["rules"][:3])</span><br></span><span class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">PY'</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="12-用-npm-反代规则文件">12. 用 NPM 反代规则文件<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#12-%E7%94%A8-npm-%E5%8F%8D%E4%BB%A3%E8%A7%84%E5%88%99%E6%96%87%E4%BB%B6" class="hash-link" aria-label="12. 用 NPM 反代规则文件的直接链接" title="12. 用 NPM 反代规则文件的直接链接" translate="no">​</a></h2>
<p>目标是让客户端访问：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">https://&lt;PROXY_DOMAIN&gt;/rules/google.txt</span><br></span></code></pre></div></div>
<p>实际由 NPM 去请求：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/google.txt</span><br></span></code></pre></div></div>
<p>这样客户端只需要能访问你的域名，不必直接访问 GitHub 或 jsDelivr。我们只放行固定规则文件名，不做开放代理。</p>
<p>创建 NPM 自定义配置目录：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">mkdir</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-p</span><span class="token plain"> /home/projects/nginx/data/nginx/custom</span><br></span></code></pre></div></div>
<p>写入 <code>/home/projects/nginx/data/nginx/custom/server_proxy.conf</code>：</p>
<div class="language-nginx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-nginx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">location ~ ^/rules/(reject|private|icloud|apple|google|proxy|direct|gfw|tld-not-cn|lancidr|cncidr|telegramcidr)\.txt$ {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    if ($host != "&lt;PROXY_DOMAIN&gt;") {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        return 404;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    resolver 1.1.1.1 8.8.8.8 valid=300s ipv6=off;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    set $rules_host "cdn.jsdelivr.net";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    set $rules_name $1;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_ssl_server_name on;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_ssl_name $rules_host;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header Host $rules_host;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header User-Agent "nginx-proxy-manager-rules-proxy";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header Accept "*/*";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_buffering on;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_read_timeout 60s;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_send_timeout 60s;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_hide_header Access-Control-Allow-Origin;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    add_header Access-Control-Allow-Origin "*" always;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    add_header Cache-Control "public, max-age=3600" always;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_pass https://$rules_host/gh/Loyalsoldier/clash-rules@release/$rules_name.txt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>重要细节：文件名必须是：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">server_proxy.conf</span><br></span></code></pre></div></div>
<p>不要命名成 <code>server_proxy[.]conf</code>。NPM 生成配置里的 <code>include /data/nginx/custom/server_proxy[.]conf;</code> 是 Nginx glob 写法，实际匹配的是 <code>server_proxy.conf</code>。</p>
<p>检查并 reload：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> </span><span class="token builtin class-name">exec</span><span class="token plain"> nginx-proxy-manager nginx </span><span class="token parameter variable" style="color:#36acaa">-t</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> </span><span class="token builtin class-name">exec</span><span class="token plain"> nginx-proxy-manager nginx </span><span class="token parameter variable" style="color:#36acaa">-s</span><span class="token plain"> reload</span><br></span></code></pre></div></div>
<p>验证：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">curl</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-ksS</span><span class="token plain"> https://</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PROXY_DOMAIN</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">/rules/google.txt </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">head</span><br></span></code></pre></div></div>
<p>应该看到：</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">payload</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">...</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="13-修复订阅名称显示异常">13. 修复订阅名称显示异常<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#13-%E4%BF%AE%E5%A4%8D%E8%AE%A2%E9%98%85%E5%90%8D%E7%A7%B0%E6%98%BE%E7%A4%BA%E5%BC%82%E5%B8%B8" class="hash-link" aria-label="13. 修复订阅名称显示异常的直接链接" title="13. 修复订阅名称显示异常的直接链接" translate="no">​</a></h2>
<p>有些客户端会把响应头：</p>
<div class="language-http codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-http codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">content-disposition: attachment; filename="&lt;USERNAME&gt;"</span><br></span></code></pre></div></div>
<p>解析成奇怪的名字，比如 <code>\"&lt;USERNAME&gt;\</code>。可以在 NPM 同一个 <code>server_proxy.conf</code> 中继续追加：</p>
<div class="language-nginx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-nginx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">location ~ ^/sub/([^/]+)/[^/]+(/(sing-box|clash-meta|clash|xray|v2ray|links|wireguard))?/?$ {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    set $subscription_username $1;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header Host $host;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header X-Forwarded-Scheme $scheme;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header X-Forwarded-Proto $scheme;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header X-Real-IP $remote_addr;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_http_version 1.1;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_hide_header Content-Disposition;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    add_header Content-Disposition "attachment; filename=$subscription_username" always;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    proxy_pass http://172.17.0.1:8000;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>完整的 <code>/home/projects/nginx/data/nginx/custom/server_proxy.conf</code> 应该同时包含 <code>/rules/</code> 和 <code>/sub/</code> 两段 location。</p>
<p>再次 reload：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> </span><span class="token builtin class-name">exec</span><span class="token plain"> nginx-proxy-manager nginx </span><span class="token parameter variable" style="color:#36acaa">-t</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> </span><span class="token builtin class-name">exec</span><span class="token plain"> nginx-proxy-manager nginx </span><span class="token parameter variable" style="color:#36acaa">-s</span><span class="token plain"> reload</span><br></span></code></pre></div></div>
<p>验证订阅响应头：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token assign-left variable" style="color:#36acaa">KEY</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"&lt;USER_KEY&gt;"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">curl</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-ksS</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-D</span><span class="token plain"> - </span><span class="token parameter variable" style="color:#36acaa">-o</span><span class="token plain"> /dev/null </span><span class="token parameter variable" style="color:#36acaa">-A</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Clash-Verge/2.0'</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://&lt;PROXY_DOMAIN&gt;/sub/&lt;USERNAME&gt;/</span><span class="token string variable" style="color:#36acaa">$KEY</span><span class="token string" style="color:#e3116c">"</span><br></span></code></pre></div></div>
<p>应该看到：</p>
<div class="language-http codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-http codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Content-Disposition: attachment; filename=&lt;USERNAME&gt;</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="14-客户端使用方式">14. 客户端使用方式<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#14-%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F" class="hash-link" aria-label="14. 客户端使用方式的直接链接" title="14. 客户端使用方式的直接链接" translate="no">​</a></h2>
<p>以 Clash Verge / Mihomo 为例：</p>
<ol>
<li class="">
<p>添加订阅链接：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">https://&lt;PROXY_DOMAIN&gt;/sub/&lt;USERNAME&gt;/&lt;USER_KEY&gt;</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>刷新订阅。</p>
</li>
<li class="">
<p>使用 <code>Rule / 规则</code> 模式。</p>
</li>
<li class="">
<p>TUN 可以开启。</p>
</li>
<li class="">
<p>系统代理可以不开，TUN 会接管。</p>
</li>
<li class="">
<p>在代理组里，把 <code>Proxy</code> 选成 <code>Automatic</code>。</p>
</li>
</ol>
<p>预期结果：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Google / OpenAI / Telegram / GFW 列表：走代理</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">百度 / 国内 IP / 常见国内域名：直连</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">兜底 MATCH：走 Proxy</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="15-验证命令">15. 验证命令<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#15-%E9%AA%8C%E8%AF%81%E5%91%BD%E4%BB%A4" class="hash-link" aria-label="15. 验证命令的直接链接" title="15. 验证命令的直接链接" translate="no">​</a></h2>
<p>检查服务运行：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ps</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--filter</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">nginx-proxy-manager</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ps</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--filter</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">marzneshin</span><br></span></code></pre></div></div>
<p>检查监听：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ss </span><span class="token parameter variable" style="color:#36acaa">-tulpen</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">grep</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-E</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'(:80 |:443 |:8000 |:2087 |:81 )'</span><br></span></code></pre></div></div>
<p>理想状态：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">0.0.0.0:80        NPM</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">0.0.0.0:443       NPM</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">127.0.0.1:81      NPM 管理后台</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">172.17.0.1:8000   Marzneshin 面板</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">172.17.0.1:2087   Xray WS 后端</span><br></span></code></pre></div></div>
<p>检查面板：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">curl</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-ksS</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-o</span><span class="token plain"> /dev/null </span><span class="token parameter variable" style="color:#36acaa">-w</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'%{http_code}\n'</span><span class="token plain"> https://</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PROXY_DOMAIN</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">/dashboard/</span><br></span></code></pre></div></div>
<p>应该返回：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">200</span><br></span></code></pre></div></div>
<p>检查规则文件反代：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token for-or-select variable" style="color:#36acaa">f</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> google proxy direct cncidr telegramcidr</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">do</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token builtin class-name">printf</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"</span><span class="token string variable" style="color:#36acaa">$f</span><span class="token string" style="color:#e3116c"> "</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">curl</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-ksS</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-o</span><span class="token plain"> /dev/null </span><span class="token parameter variable" style="color:#36acaa">-w</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'%{http_code} %{size_download}\n'</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://&lt;PROXY_DOMAIN&gt;/rules/</span><span class="token string variable" style="color:#36acaa">$f</span><span class="token string" style="color:#e3116c">.txt"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">done</span><br></span></code></pre></div></div>
<p>应该都是 <code>200</code>。</p>
<p>检查订阅是否是 Clash Meta 且带规则：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token assign-left variable" style="color:#36acaa">KEY</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"&lt;USER_KEY&gt;"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">curl</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-ksS</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-A</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Clash-Verge/2.0'</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://&lt;PROXY_DOMAIN&gt;/sub/&lt;USERNAME&gt;/</span><span class="token string variable" style="color:#36acaa">$KEY</span><span class="token string" style="color:#e3116c">"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> /tmp/subscription.yml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">grep</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-E</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'^(mode:|proxies:|proxy-groups:|rule-providers:|rules:)'</span><span class="token plain"> /tmp/subscription.yml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">grep</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'type: vless'</span><span class="token plain"> /tmp/subscription.yml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">grep</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'RULE-SET,google,Proxy'</span><span class="token plain"> /tmp/subscription.yml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">grep</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'MATCH,Proxy'</span><span class="token plain"> /tmp/subscription.yml</span><br></span></code></pre></div></div>
<p>应该能看到：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">mode: rule</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">type: vless</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">RULE-SET,google,Proxy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">MATCH,Proxy</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="16-常见问题">16. 常见问题<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#16-%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98" class="hash-link" aria-label="16. 常见问题的直接链接" title="16. 常见问题的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="502-bad-gateway">502 Bad Gateway<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#502-bad-gateway" class="hash-link" aria-label="502 Bad Gateway的直接链接" title="502 Bad Gateway的直接链接" translate="no">​</a></h3>
<p>最常见原因是 NPM 容器访问不到后端。</p>
<p>在这套方案里，不建议在 NPM 里把 Marzneshin 后端写成 <code>&lt;PROXY_DOMAIN&gt;:8000</code>，那会绕回公网域名，也可能形成错误转发。也不建议依赖 <code>host.docker.internal</code>，因为 NPM 生成的动态 <code>proxy_pass</code> 场景中，Nginx 的 resolver 不一定按 <code>/etc/hosts</code> 解析它。</p>
<p>推荐固定写：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">172.17.0.1:8000</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">172.17.0.1:2087</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="延迟测试正常但-google-打不开">延迟测试正常，但 Google 打不开<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#%E5%BB%B6%E8%BF%9F%E6%B5%8B%E8%AF%95%E6%AD%A3%E5%B8%B8%E4%BD%86-google-%E6%89%93%E4%B8%8D%E5%BC%80" class="hash-link" aria-label="延迟测试正常，但 Google 打不开的直接链接" title="延迟测试正常，但 Google 打不开的直接链接" translate="no">​</a></h3>
<p>这通常不是服务器节点问题，而是客户端分流规则问题。</p>
<p>如果全局模式可以打开 Google，规则模式打不开，说明订阅没有正确带规则，或者规则源下载失败。检查：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">curl</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-ksS</span><span class="token plain"> https://</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">PROXY_DOMAIN</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">/rules/google.txt </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">head</span><br></span></code></pre></div></div>
<p>以及客户端里规则源是否更新成功。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="订阅里-proxies-">订阅里 <code>proxies: []</code><a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#%E8%AE%A2%E9%98%85%E9%87%8C-proxies-" class="hash-link" aria-label="订阅里-proxies-的直接链接" title="订阅里-proxies-的直接链接" translate="no">​</a></h3>
<p>大概率是客户端 User-Agent 没匹配到 <code>clash-meta</code>，回落到了 classic Clash。VLESS 需要 Clash Meta / Mihomo。检查订阅规则：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">(?i)^(clash[ .-]?verge|clash[ .-]?meta|mihomo) -&gt; clash-meta</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="npm-自定义配置不生效">NPM 自定义配置不生效<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#npm-%E8%87%AA%E5%AE%9A%E4%B9%89%E9%85%8D%E7%BD%AE%E4%B8%8D%E7%94%9F%E6%95%88" class="hash-link" aria-label="NPM 自定义配置不生效的直接链接" title="NPM 自定义配置不生效的直接链接" translate="no">​</a></h3>
<p>确认文件名：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">ls</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-l</span><span class="token plain"> /home/projects/nginx/data/nginx/custom/server_proxy.conf</span><br></span></code></pre></div></div>
<p>然后：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> </span><span class="token builtin class-name">exec</span><span class="token plain"> nginx-proxy-manager nginx </span><span class="token parameter variable" style="color:#36acaa">-T</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">grep</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-n</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'location ~ \^/rules'</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-A</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">30</span><br></span></code></pre></div></div>
<p>如果看不到 <code>/rules/</code> location，说明 include 没匹配到。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="升级-marzneshin-后订阅规则丢失">升级 Marzneshin 后订阅规则丢失<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#%E5%8D%87%E7%BA%A7-marzneshin-%E5%90%8E%E8%AE%A2%E9%98%85%E8%A7%84%E5%88%99%E4%B8%A2%E5%A4%B1" class="hash-link" aria-label="升级 Marzneshin 后订阅规则丢失的直接链接" title="升级 Marzneshin 后订阅规则丢失的直接链接" translate="no">​</a></h3>
<p>本文的补丁通过：</p>
<div class="language-dotenv codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dotenv codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">PYTHONPATH="/var/lib/marzneshin/patches"</span><br></span></code></pre></div></div>
<p>挂载在 <code>/var/lib/marzneshin</code>，不会因为容器重建丢失。但如果 Marzneshin 后续底层生成逻辑变动，建议升级后重新验证：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">curl</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-ksS</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-A</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Clash-Verge/2.0'</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://&lt;PROXY_DOMAIN&gt;/sub/&lt;USERNAME&gt;/&lt;USER_KEY&gt;"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">grep</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-E</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'RULE-SET|type: vless|mode: rule'</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="17-当前最终文件清单">17. 当前最终文件清单<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#17-%E5%BD%93%E5%89%8D%E6%9C%80%E7%BB%88%E6%96%87%E4%BB%B6%E6%B8%85%E5%8D%95" class="hash-link" aria-label="17. 当前最终文件清单的直接链接" title="17. 当前最终文件清单的直接链接" translate="no">​</a></h2>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">/etc/opt/marzneshin/docker-compose.yml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/etc/opt/marzneshin/.env</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/var/lib/marzneshin/templates/clash.yml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/var/lib/marzneshin/patches/sitecustomize.py</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/home/projects/nginx/docker-compose.yml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">/home/projects/nginx/data/nginx/custom/server_proxy.conf</span><br></span></code></pre></div></div>
<p>最终公网只需要开放：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">80/tcp</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">443/tcp</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">22/tcp  # SSH，建议限制来源 IP 或改用密钥</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="18-参考资料">18. 参考资料<a href="https://your-docusaurus-site.example.com/marzneshin-npm-vless-ws-tls-guide#18-%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99" class="hash-link" aria-label="18. 参考资料的直接链接" title="18. 参考资料的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://docs.marzneshin.org/docs/getting-started/basic-install/" target="_blank" rel="noopener noreferrer" class="">Marzneshin 官方基础安装文档</a></li>
<li class=""><a href="https://docs.marzneshin.org/docs/how-to-guides/behind-nginx/" target="_blank" rel="noopener noreferrer" class="">Marzneshin 官方 Nginx 反代文档</a></li>
<li class=""><a href="https://docs.docker.com/compose/" target="_blank" rel="noopener noreferrer" class="">Docker Compose 官方文档</a></li>
<li class=""><a href="https://github.com/Loyalsoldier/clash-rules" target="_blank" rel="noopener noreferrer" class="">Loyalsoldier Clash 规则</a></li>
</ul>]]></content>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="marzneshin" term="marzneshin"/>
        <category label="vless" term="vless"/>
        <category label="clash verge" term="clash verge"/>
        <category label="mihomo" term="mihomo"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Clash TUN 模式下微信收发图片变慢：一次 IPv6 排查记录]]></title>
        <id>https://your-docusaurus-site.example.com/clash-tun-wechat-image-slow-ipv6</id>
        <link href="https://your-docusaurus-site.example.com/clash-tun-wechat-image-slow-ipv6"/>
        <updated>2026-05-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[最近我在 Clash Verge / Mihomo 中开启了 TUN 模式后，发现微信收发图片明显变慢。一开始我怀疑是微信图片流量被代理服务器接管了，导致绕路。]]></summary>
        <content type="html"><![CDATA[<p>最近我在 Clash Verge / Mihomo 中开启了 TUN 模式后，发现微信收发图片明显变慢。一开始我怀疑是微信图片流量被代理服务器接管了，导致绕路。</p>
<p>但排查日志后发现，真正的问题并不是“微信走了代理”，而是 Clash 中开启 IPv6 后，让微信尝试了一条当前网络环境不可达的 IPv6 路径。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="现象">现象<a href="https://your-docusaurus-site.example.com/clash-tun-wechat-image-slow-ipv6#%E7%8E%B0%E8%B1%A1" class="hash-link" aria-label="现象的直接链接" title="现象的直接链接" translate="no">​</a></h2>
<p>开启 Clash TUN 模式后：</p>
<ul>
<li class="">微信文字消息基本正常</li>
<li class="">接收和发送图片明显变慢</li>
<li class="">关闭 Clash 中的 IPv6 后，微信图片恢复正常</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="排查过程">排查过程<a href="https://your-docusaurus-site.example.com/clash-tun-wechat-image-slow-ipv6#%E6%8E%92%E6%9F%A5%E8%BF%87%E7%A8%8B" class="hash-link" aria-label="排查过程的直接链接" title="排查过程的直接链接" translate="no">​</a></h2>
<p>先查看 Clash / Mihomo 的规则和连接日志。</p>
<p>配置中微信相关进程已经被明确设置为直连：</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> PROCESS</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">NAME</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Weixin.exe</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> PROCESS</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">NAME</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">WeixinUpdate.exe</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> PROCESS</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">NAME</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">WeChatAppEx.exe</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> PROCESS</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">NAME</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">WeixinExt.exe</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">DIRECT</span><br></span></code></pre></div></div>
<p>随后在微信接收一张图片时，对比 Mihomo 日志，发现新增记录类似这样：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[TCP] dial DIRECT (match ProcessName/Weixin.exe)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Weixin.exe --&gt; [240e:xxxx:xxxx::xxxx]:443</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">error: connect failed: dial tcp [240e:xxxx:xxxx::xxxx]:443:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">A socket operation was attempted to an unreachable network.</span><br></span></code></pre></div></div>
<p>关键信息有三个：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ProcessName/Weixin.exe</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">IPv6 unreachable network</span><br></span></code></pre></div></div>
<p>也就是说，微信并没有走代理，而是命中了 <code>DIRECT</code> 规则。但它尝试访问腾讯/微信的 IPv6 地址时，当前网络环境下这条 IPv6 路径不可达，于是发生反复重试，最终造成图片收发很慢。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="真正原因">真正原因<a href="https://your-docusaurus-site.example.com/clash-tun-wechat-image-slow-ipv6#%E7%9C%9F%E6%AD%A3%E5%8E%9F%E5%9B%A0" class="hash-link" aria-label="真正原因的直接链接" title="真正原因的直接链接" translate="no">​</a></h2>
<p>问题不是：</p>
<ul>
<li class="">微信图片走了代理</li>
<li class="">代理服务器太慢</li>
<li class="">微信服务器慢</li>
</ul>
<p>更准确的原因是：</p>
<blockquote>
<p>Clash / Mihomo 中开启 IPv6 后，微信拿到了 IPv6 目标地址，并尝试直连；但当前 TUN / 网络环境无法真正访问这些 IPv6 地址，于是连接失败、重试、回落，造成明显延迟。</p>
</blockquote>
<p>这是一种“看起来支持 IPv6，但实际路径不可达”的情况。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="解决方式">解决方式<a href="https://your-docusaurus-site.example.com/clash-tun-wechat-image-slow-ipv6#%E8%A7%A3%E5%86%B3%E6%96%B9%E5%BC%8F" class="hash-link" aria-label="解决方式的直接链接" title="解决方式的直接链接" translate="no">​</a></h2>
<p>在 Clash / Mihomo 中关闭 IPv6：</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">ipv6</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">dns</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">ipv6</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">false</span><br></span></code></pre></div></div>
<p>然后重启 Clash 内核。</p>
<p>注意，这里说的是关闭 Clash / Mihomo 内部的 IPv6 支持，不是去 Windows 网卡里全局禁用 IPv6。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="关闭-clash-ipv6-会有什么影响">关闭 Clash IPv6 会有什么影响？<a href="https://your-docusaurus-site.example.com/clash-tun-wechat-image-slow-ipv6#%E5%85%B3%E9%97%AD-clash-ipv6-%E4%BC%9A%E6%9C%89%E4%BB%80%E4%B9%88%E5%BD%B1%E5%93%8D" class="hash-link" aria-label="关闭 Clash IPv6 会有什么影响？的直接链接" title="关闭 Clash IPv6 会有什么影响？的直接链接" translate="no">​</a></h2>
<p>关闭后，Clash 通常不再处理 IPv6 目标地址，也不会主动返回 IPv6 DNS 结果。大多数应用会回落到 IPv4。</p>
<p>影响一般是：</p>
<ul>
<li class="">IPv4 代理规则仍然正常工作</li>
<li class="">大多数网站和 App 不受影响</li>
<li class="">少数 IPv6-only 服务可能无法访问</li>
<li class="">如果某些服务 IPv6 路径原本更优，可能失去这部分优势</li>
<li class="">但在当前网络 IPv6 不通的情况下，关闭反而更稳定</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="代理本身是否支持-ipv6">代理本身是否支持 IPv6？<a href="https://your-docusaurus-site.example.com/clash-tun-wechat-image-slow-ipv6#%E4%BB%A3%E7%90%86%E6%9C%AC%E8%BA%AB%E6%98%AF%E5%90%A6%E6%94%AF%E6%8C%81-ipv6" class="hash-link" aria-label="代理本身是否支持 IPv6？的直接链接" title="代理本身是否支持 IPv6？的直接链接" translate="no">​</a></h2>
<p>不能只看代理节点入口 IP 来判断。</p>
<p>即使代理服务器入口是 IPv4，比如：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">104.xxx.xxx.xxx:4431</span><br></span></code></pre></div></div>
<p>它也可能支持代理 IPv6 目标地址。是否支持取决于：</p>
<ul>
<li class="">节点服务器是否有 IPv6 出站能力</li>
<li class="">代理协议和服务端配置是否支持</li>
<li class="">Clash/Mihomo 是否开启 IPv6 处理</li>
</ul>
<p>在这次问题里，微信本身命中的是 <code>DIRECT</code>，所以重点并不是“节点是否支持 IPv6”，而是“微信直连 IPv6 不可达”。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://your-docusaurus-site.example.com/clash-tun-wechat-image-slow-ipv6#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>这次微信图片慢的核心链路是：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Clash 开启 IPv6</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ↓</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">微信拿到 IPv6 地址</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ↓</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">微信按规则 DIRECT 直连</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ↓</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">当前网络/TUN 环境 IPv6 不可达</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ↓</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">连接失败、重试、回落</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ↓</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">收发图片变慢</span><br></span></code></pre></div></div>
<p>关闭 Clash 中的 IPv6 后，微信更早走 IPv4，绕过不可达的 IPv6 路径，问题解决。</p>
<p>如果你也遇到 Clash TUN 模式下微信、QQ、国内 App 图片或资源加载很慢，可以优先检查 Mihomo 日志中是否存在类似：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">DIRECT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">IPv6</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">unreachable network</span><br></span></code></pre></div></div>
<p>如果有，那么关闭 Clash / Mihomo 的 IPv6 很可能就是最直接的解决办法。</p>]]></content>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="微信" term="微信"/>
        <category label="clash" term="clash"/>
        <category label="clash verge" term="clash verge"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[让应用程序绕过 Clash Verge 代理（TUN / 系统代理通用方案）]]></title>
        <id>https://your-docusaurus-site.example.com/bypassing-clash-verge-proxy-for-selected-applications</id>
        <link href="https://your-docusaurus-site.example.com/bypassing-clash-verge-proxy-for-selected-applications"/>
        <updated>2026-04-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[背景]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="背景">背景<a href="https://your-docusaurus-site.example.com/bypassing-clash-verge-proxy-for-selected-applications#%E8%83%8C%E6%99%AF" class="hash-link" aria-label="背景的直接链接" title="背景的直接链接" translate="no">​</a></h2>
<p>在开启 TUN 模式或系统代理模式时，部分应用（如微信、Radmin VPN）可能出现：</p>
<ul>
<li class="">文件传输缓慢或失败</li>
<li class="">局域网通信异常</li>
<li class="">VPN 无法建立连接</li>
</ul>
<p>本文提供一套<strong>通用方案</strong>，使指定应用绕过 Clash Verge 代理。</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="步骤-1配置-tun-排除进程">步骤 1：配置 TUN 排除进程<a href="https://your-docusaurus-site.example.com/bypassing-clash-verge-proxy-for-selected-applications#%E6%AD%A5%E9%AA%A4-1%E9%85%8D%E7%BD%AE-tun-%E6%8E%92%E9%99%A4%E8%BF%9B%E7%A8%8B" class="hash-link" aria-label="步骤 1：配置 TUN 排除进程的直接链接" title="步骤 1：配置 TUN 排除进程的直接链接" translate="no">​</a></h2>
<p>打开「订阅」→「全局扩展覆写配置」，覆盖粘贴：</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Profile Enhancement Merge Template for Clash Verge</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">profile</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">store-selected</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># ✅ 关键：让 Radmin VPN 不被 TUN 接管</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">tun</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">exclude-process</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> AnyDesk.exe</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> WeChatAppEx.exe</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> WeixinUpdate.exe</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> Weixin.exe</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> WetypeInstaller.exe</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> WeixinExt.exe</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RvRvpnGui.exe</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RvControlSvc.exe</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> Radmin.exe</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> drvinst.exe</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RvFwHelper.exe</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> RvGuiStarter.exe</span><br></span></code></pre></div></div>
<p>👉 作用：这些进程不会被 TUN 模式接管</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="步骤-2添加规则强制直连">步骤 2：添加规则强制直连<a href="https://your-docusaurus-site.example.com/bypassing-clash-verge-proxy-for-selected-applications#%E6%AD%A5%E9%AA%A4-2%E6%B7%BB%E5%8A%A0%E8%A7%84%E5%88%99%E5%BC%BA%E5%88%B6%E7%9B%B4%E8%BF%9E" class="hash-link" aria-label="步骤 2：添加规则强制直连的直接链接" title="步骤 2：添加规则强制直连的直接链接" translate="no">​</a></h2>
<p>打开「全局扩展脚本」，覆盖粘贴：</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Define main function (script entry)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">config</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> profileName</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 为所有代理节点添加或设置 'udp: true'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">proxies</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">proxies</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">proxy</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">proxy</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">udp</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">rules</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">??=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 保留原有的添加域名规则的逻辑</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"proxy-groups"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">?.</span><span class="token method function property-access" style="color:#d73a49">at</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> excludeProcesses </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"AnyDesk.exe"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"WeChatAppEx.exe"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"WeixinUpdate.exe"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"Weixin.exe"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"WetypeInstaller.exe"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"WeixinExt.exe"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"RvRvpnGui.exe"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"RvControlSvc.exe"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"Radmin.exe"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"drvinst.exe"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"RvFwHelper.exe"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string" style="color:#e3116c">"RvGuiStarter.exe"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">rules</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">unshift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">DOMAIN-SUFFIX,claude.ai,</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">rules</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">unshift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">DOMAIN-SUFFIX,claude.com,</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">rules</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">unshift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">IP-CIDR,26.0.0.0/8,DIRECT</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        excludeProcesses</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">item</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">rules</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">unshift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">PROCESS-NAME,</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">item</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c">,DIRECT</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> config</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>👉 作用：</p>
<ul>
<li class="">强制指定进程走直连</li>
<li class="">即使切换到“代理模式”仍然生效</li>
</ul>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="步骤-3可选调整-dns-模式">步骤 3（可选）：调整 DNS 模式<a href="https://your-docusaurus-site.example.com/bypassing-clash-verge-proxy-for-selected-applications#%E6%AD%A5%E9%AA%A4-3%E5%8F%AF%E9%80%89%E8%B0%83%E6%95%B4-dns-%E6%A8%A1%E5%BC%8F" class="hash-link" aria-label="步骤 3（可选）：调整 DNS 模式的直接链接" title="步骤 3（可选）：调整 DNS 模式的直接链接" translate="no">​</a></h2>
<p>打开「设置」→「DNS 覆写」，将：</p>
<ul>
<li class=""><code>fake-ip</code> → <code>redir-host</code></li>
</ul>
<p>👉 适用于以下情况：</p>
<ul>
<li class="">微信传文件异常</li>
<li class="">局域网通信不稳定</li>
</ul>
<p>⚠️ 注意：</p>
<ul>
<li class="">此步骤为可选项</li>
<li class="">如果修改后出现网络异常，可以恢复为 <code>fake-ip</code></li>
</ul>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="验证是否生效">验证是否生效<a href="https://your-docusaurus-site.example.com/bypassing-clash-verge-proxy-for-selected-applications#%E9%AA%8C%E8%AF%81%E6%98%AF%E5%90%A6%E7%94%9F%E6%95%88" class="hash-link" aria-label="验证是否生效的直接链接" title="验证是否生效的直接链接" translate="no">​</a></h2>
<p>可以通过以下方式确认：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-测试-radmin-vpn">1. 测试 Radmin VPN<a href="https://your-docusaurus-site.example.com/bypassing-clash-verge-proxy-for-selected-applications#1-%E6%B5%8B%E8%AF%95-radmin-vpn" class="hash-link" aria-label="1. 测试 Radmin VPN的直接链接" title="1. 测试 Radmin VPN的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">ping</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">26</span><span class="token plain">.x.x.x</span><br></span></code></pre></div></div>
<p>应正常通信。</p>
<hr>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-查看-clash-日志">2. 查看 Clash 日志<a href="https://your-docusaurus-site.example.com/bypassing-clash-verge-proxy-for-selected-applications#2-%E6%9F%A5%E7%9C%8B-clash-%E6%97%A5%E5%BF%97" class="hash-link" aria-label="2. 查看 Clash 日志的直接链接" title="2. 查看 Clash 日志的直接链接" translate="no">​</a></h3>
<p>在日志中应看到：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">26.x.x.x → DIRECT</span><br></span></code></pre></div></div>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="原理说明">原理说明<a href="https://your-docusaurus-site.example.com/bypassing-clash-verge-proxy-for-selected-applications#%E5%8E%9F%E7%90%86%E8%AF%B4%E6%98%8E" class="hash-link" aria-label="原理说明的直接链接" title="原理说明的直接链接" translate="no">​</a></h2>
<p>本方案基于三点：</p>
<ol>
<li class="">
<p><code>tun.exclude-process</code></p>
<ul>
<li class="">控制流量是否进入 Clash（入口）</li>
</ul>
</li>
<li class="">
<p><code>PROCESS-NAME,...,DIRECT</code></p>
<ul>
<li class="">控制流量走直连（出口）</li>
</ul>
</li>
<li class="">
<p><code>IP-CIDR,26.0.0.0/8,DIRECT</code></p>
<ul>
<li class="">确保 Radmin VPN 内网流量不被代理</li>
</ul>
</li>
</ol>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://your-docusaurus-site.example.com/bypassing-clash-verge-proxy-for-selected-applications#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<ul>
<li class="">TUN 排除：避免应用被接管</li>
<li class="">规则直连：保证任何模式下都不走代理</li>
<li class="">DNS 调整：作为兼容性优化手段</li>
</ul>
<p>通过以上配置，可以实现 Clash Verge 与微信、Radmin VPN 等应用的稳定共存。</p>]]></content>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="微信" term="微信"/>
        <category label="clash" term="clash"/>
        <category label="clash verge" term="clash verge"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[函数默认参数值]]></title>
        <id>https://your-docusaurus-site.example.com/default-parameter-value</id>
        <link href="https://your-docusaurus-site.example.com/default-parameter-value"/>
        <updated>2026-02-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[一直以来有一个很困惑的问题，那就是函数的默认参数值是动态创建的么？测试一下：]]></summary>
        <content type="html"><![CDATA[<p>一直以来有一个很困惑的问题，那就是函数的默认参数值是动态创建的么？测试一下：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>结果是 <code>false</code>，所以函数的默认参数值是动态创建的。</p>
<p>同理，解构赋值也是动态创建的：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">Info</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    data</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> info</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Info </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getData</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Info</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> data</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getData</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">info</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> d </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getData</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">info</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">c </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> d</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>结果是 <code>false</code>，所以解构赋值也是动态创建的。</p>]]></content>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="typescript" term="typescript"/>
        <category label="default-parameter-value" term="default-parameter-value"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[开启 React Compiler 之后的 TanStack Query]]></title>
        <id>https://your-docusaurus-site.example.com/react-compiler-with-tanstack-query</id>
        <link href="https://your-docusaurus-site.example.com/react-compiler-with-tanstack-query"/>
        <updated>2026-02-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[开启 React Compiler 之后，TanStack Query 的 select 方法也会被 React Compiler 优化，详情以下代码在 React Compiler 开启与关闭下的区别：]]></summary>
        <content type="html"><![CDATA[<p>开启 <a href="https://zh-hans.react.dev/learn/react-compiler" target="_blank" rel="noopener noreferrer" class="">React Compiler</a> 之后，<a href="https://tanstack.com/query/latest" target="_blank" rel="noopener noreferrer" class="">TanStack Query</a> 的 <code>select</code> 方法也会被 React Compiler 优化，详情以下代码在 React Compiler 开启与关闭下的区别：</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">FC</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> useState </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> useQuery </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@tanstack/react-query"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getData</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token known-class-name class-name">Promise</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">resolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">123456</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token maybe-class-name">Page</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">FC</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">count</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setCount</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> data </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useQuery</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        queryKey</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"get-data"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        queryFn</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> getData</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function-variable function" style="color:#d73a49">select</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token known-class-name class-name">Date</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">now</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">            </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">now: </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">            </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">count: </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">count</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">            </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">                </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript function" style="color:#d73a49">setCount</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript" style="color:#00009f">count </span><span class="token tag script language-javascript operator" style="color:#393A34">+</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript number" style="color:#36acaa">1</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">add</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">            </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token maybe-class-name">Page</span><br></span></code></pre></div></div>
<p>当然我的 <code>soda-tanstack-query</code> 也是可以享受这个优化的。</p>]]></content>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="react" term="react"/>
        <category label="tanstack-query" term="tanstack-query"/>
        <category label="react-compiler" term="react-compiler"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[通过 AI SDK 发送自定义数据和元数据]]></title>
        <id>https://your-docusaurus-site.example.com/transport-metadata-and-custom-data-with-ai-sdk</id>
        <link href="https://your-docusaurus-site.example.com/transport-metadata-and-custom-data-with-ai-sdk"/>
        <updated>2025-12-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Vercel 的 AI SDK 很方便，把前后端的代码都封装起来了，但是有一点不好，就是文档写得不够详细，只介绍了一些初级用法，稍微复杂一点的用法就需要自己去探索。]]></summary>
        <content type="html"><![CDATA[<p>Vercel 的 AI SDK 很方便，把前后端的代码都封装起来了，但是有一点不好，就是文档写得不够详细，只介绍了一些初级用法，稍微复杂一点的用法就需要自己去探索。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="uimessage">UIMessage<a href="https://your-docusaurus-site.example.com/transport-metadata-and-custom-data-with-ai-sdk#uimessage" class="hash-link" aria-label="UIMessage的直接链接" title="UIMessage的直接链接" translate="no">​</a></h2>
<p><code>UIMessage</code> 是 AI SDK 中的消息类型，是最核心的内容。</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">The data types that can be used in the UI message for the UI message data parts.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">UIDataTypes</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">unknown</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">UITools</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> UITool</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">AI SDK UI Messages. They are used in the client and to communicate between the frontend and the API routes.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">UIMessage</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">METADATA</span><span class="token class-name"> </span><span class="token class-name operator" style="color:#393A34">=</span><span class="token class-name"> </span><span class="token class-name builtin">unknown</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"> </span><span class="token class-name constant" style="color:#36acaa">DATA_PARTS</span><span class="token class-name"> </span><span class="token class-name keyword" style="color:#00009f">extends</span><span class="token class-name"> UIDataTypes </span><span class="token class-name operator" style="color:#393A34">=</span><span class="token class-name"> UIDataTypes</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"> </span><span class="token class-name constant" style="color:#36acaa">TOOLS</span><span class="token class-name"> </span><span class="token class-name keyword" style="color:#00009f">extends</span><span class="token class-name"> UITools </span><span class="token class-name operator" style="color:#393A34">=</span><span class="token class-name"> UITools</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">  A unique identifier for the message.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">     */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">  The role of the message.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">     */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    role</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"system"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"user"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"assistant"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">  The metadata of the message.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">     */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    metadata</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">METADATA</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token doc-comment comment" style="color:#999988;font-style:italic">/**</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">  The parts of the message. Use this for rendering the message in the UI.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">  System messages should be avoided (set the system prompt on the server instead).</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">  They can have text parts.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">  User messages can have text parts and file parts.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">  Assistant messages can have text, reasoning, tool invocation, and file parts.</span><br></span><span class="token-line" style="color:#393A34"><span class="token doc-comment comment" style="color:#999988;font-style:italic">     */</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    parts</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">Array</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">UIMessagePart</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">DATA_PARTS</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">TOOLS</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p><code>UIMessage</code> 接受三个泛型参数：</p>
<ul>
<li class=""><code>METADATA</code>：消息的元数据</li>
<li class=""><code>DATA_PARTS</code>：消息的数据部分</li>
<li class=""><code>TOOLS</code>：消息的工具</li>
</ul>
<p>以下使我们创建的一个定义消息类型 <code>MyUIMessage</code></p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">Metadata</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    conversationId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    messageId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    modelIdSnapshot</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    usedTokens</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 由于 extends Record&lt;string, unknown&gt; 的限制，DataParts 不能是接口，必须是类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">DataParts</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    timestamp</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">MyUIMessage</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> UIMessage</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Metadata</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> DataParts</span><span class="token operator" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="metadata">METADATA<a href="https://your-docusaurus-site.example.com/transport-metadata-and-custom-data-with-ai-sdk#metadata" class="hash-link" aria-label="METADATA的直接链接" title="METADATA的直接链接" translate="no">​</a></h2>
<p><code>metadata</code> 就是消息的元数据，每一条消息（目前来看只有响应的消息）都可以有 <code>metadata</code> 属性，<strong><code>metadata</code> 是附加在消息级别的自定义信息，用于描述消息本身的属性，而不是消息内容的一部分</strong>，我们可以使用 <code>metadata</code> 来传递一些额外的信息，比如当前的会话 <code>id</code>。</p>
<p>特点：</p>
<ul>
<li class="">附加在 <code>message.metadata</code> 对象上</li>
<li class="">通过 <code>toUIMessageStreamResponse</code> 中的 <code>messageMetadata</code> 回调发送</li>
<li class="">描述整个消息的属性信息</li>
<li class="">持久化在消息历史中</li>
</ul>
<p>适用场景:</p>
<ul>
<li class="">适合存储时间戳、模型信息、token 使用量、用户上下文等消息级别的描述性信息</li>
</ul>
<p>使用实例：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 服务端</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">.</span><span class="token generic-function function" style="color:#d73a49">toUIMessageStreamResponse</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">MyUIMessage</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function-variable function" style="color:#d73a49">messageMetadata</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> part </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">part</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">type </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"start"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                conversationId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                messageId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                modelIdSnapshot</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"GPT-5.2"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                usedTokens</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 你可以选择更新整个 metadata</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">part</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">type </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"text"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">// 由于 metadata 并不限于对象类型，所以并不支持局部更新</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                conversationId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                messageId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                modelIdSnapshot</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"GPT-5.2"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                usedTokens</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 客户端访问</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">metadata</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>]]></content>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="vercel" term="vercel"/>
        <category label="ai-sdk" term="ai-sdk"/>
        <category label="useChat" term="useChat"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Gemini 提示词设计指南]]></title>
        <id>https://your-docusaurus-site.example.com/prompt-design-strategies</id>
        <link href="https://your-docusaurus-site.example.com/prompt-design-strategies"/>
        <updated>2025-11-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[原文地址：Gemini 提示词设计指南，以下内容均为 Claude 4.5 sonnet 翻译]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>原文地址：<a href="https://ai.google.dev/gemini-api/docs/prompting-strategies" target="_blank" rel="noopener noreferrer" class="">Gemini 提示词设计指南</a>，以下内容均为 <code>Claude 4.5 sonnet</code> 翻译</p>
</blockquote>
<p><strong>提示词设计</strong>是创建提示词（即自然语言请求）的过程，用于引导语言模型生成准确、高质量的响应。</p>
<p>本页面介绍基本概念、策略和最佳实践，帮助您开始设计提示词，以充分发挥 Gemini AI 模型的能力。</p>
<blockquote>
<p><strong>注意:</strong> 提示词工程是一个迭代过程。这些指南和模板只是起点。请根据您的具体用例和观察到的模型响应进行实验和改进。</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="特定主题的提示词指南">特定主题的提示词指南<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E7%89%B9%E5%AE%9A%E4%B8%BB%E9%A2%98%E7%9A%84%E6%8F%90%E7%A4%BA%E8%AF%8D%E6%8C%87%E5%8D%97" class="hash-link" aria-label="特定主题的提示词指南的直接链接" title="特定主题的提示词指南的直接链接" translate="no">​</a></h2>
<p>寻找更具体的提示词策略？请查看我们的其他提示词指南：</p>
<ul>
<li class=""><a href="https://ai.google.dev/gemini-api/docs/files#prompt-guide" target="_blank" rel="noopener noreferrer" class="">使用媒体文件进行提示</a></li>
<li class="">使用 <a href="https://ai.google.dev/gemini-api/docs/imagen#imagen-prompt-guide" target="_blank" rel="noopener noreferrer" class="">Imagen</a> 和 <a href="https://ai.google.dev/gemini-api/docs/image-generation#prompt-guide" target="_blank" rel="noopener noreferrer" class="">Gemini</a> 原生图像生成进行图像生成提示</li>
<li class=""><a href="https://ai.google.dev/gemini-api/docs/video#prompt-guide" target="_blank" rel="noopener noreferrer" class="">视频生成提示</a></li>
</ul>
<p>您还可以在<a href="https://ai.google.dev/gemini-api/prompts" target="_blank" rel="noopener noreferrer" class="">提示词库</a>中找到其他示例提示词，该库旨在交互式展示本指南中共享的许多概念。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="清晰具体的指令">清晰具体的指令<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E6%B8%85%E6%99%B0%E5%85%B7%E4%BD%93%E7%9A%84%E6%8C%87%E4%BB%A4" class="hash-link" aria-label="清晰具体的指令的直接链接" title="清晰具体的指令的直接链接" translate="no">​</a></h2>
<p>定制模型行为的有效且高效的方法是提供清晰具体的指令。指令可以是问题形式、分步任务，或者像描述用户体验和思维方式一样复杂。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="输入">输入<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E8%BE%93%E5%85%A5" class="hash-link" aria-label="输入的直接链接" title="输入的直接链接" translate="no">​</a></h3>
<p>输入是提示词中的必需文本，您希望模型对其提供响应。输入可以是模型回答的问题（问题输入）、模型执行的任务（任务输入）、模型操作的实体（实体输入）或模型完成或继续的部分输入（完成输入）。</p>
<table><thead><tr><th><strong>输入类型</strong></th><th><strong>提示词</strong></th><th><strong>生成的输出</strong></th></tr></thead><tbody><tr><td>问题</td><td>对于专门销售干花花束的花店，有什么好名字？创建一个包含 5 个选项的列表，只列出名称。</td><td>以下是 10 个专门经营干花的花店名称：<br>1. 永恒花开 <br>2. 干燥与愉悦 <br>3. 花瓣保存室 <br>4. 野花低语 <br>5. 永远绽放</td></tr><tr><td>任务</td><td>给我一个简单的清单，列出我在露营旅行中必须携带的物品。清单应有 5 项。</td><td>1. <strong>帐篷:</strong> 您的避难所。<br>2. <strong>睡袋:</strong> 保持温暖舒适。<br>3. <strong>睡垫:</strong> 隔热和缓冲，确保良好睡眠。<br>4. <strong>头灯或手电筒:</strong> 夜间活动照明。<br>5. <strong>急救包:</strong> 为轻微伤害做好准备。</td></tr><tr><td>实体</td><td>将以下项目分类为 [大型, 小型]：<br>大象<br>老鼠<br>蜗牛</td><td>分类如下：<br>* <strong>大象:</strong> 大型<br>* <strong>老鼠:</strong> 小型<br>* <strong>蜗牛:</strong> 小型</td></tr></tbody></table>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="部分输入完成">部分输入完成<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E9%83%A8%E5%88%86%E8%BE%93%E5%85%A5%E5%AE%8C%E6%88%90" class="hash-link" aria-label="部分输入完成的直接链接" title="部分输入完成的直接链接" translate="no">​</a></h4>
<p>生成式语言模型的工作方式类似于高级自动补全工具。当您提供部分内容时，模型可以提供其余内容或它认为是该内容的延续作为响应。在这样做时，如果您包含任何示例或上下文，模型可以将这些示例或上下文考虑在内。</p>
<p>以下示例提供了带有指令和实体输入的提示词：</p>
<p><strong>提示词：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">对于给定的订单，返回一个 JSON 对象，该对象包含 cheeseburger、hamburger、fries 或 drink 字段，值为数量。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">订单：一个汉堡和一杯饮料。</span><br></span></code></pre></div></div>
<p><strong>响应：</strong></p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"cheeseburger"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"hamburger"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"fries"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"drink"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>虽然模型按提示执行了，但用自然语言写出指令有时可能具有挑战性，并且很多内容留给模型解释。例如，餐厅菜单可能包含许多项目。为了减小 JSON 响应的大小，您可能希望省略未订购的项目。在这种情况下，您可以给出一个示例和<a href="https://ai.google.dev/gemini-api/docs/prompting-strategies#prefixes" target="_blank" rel="noopener noreferrer" class="">响应前缀</a>，让模型完成它：</p>
<p><strong>提示词：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">有效字段为 cheeseburger、hamburger、fries 和 drink。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">订单：给我一个芝士汉堡和薯条</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">输出：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">```json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "cheeseburger": 1,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "fries": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">```</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">订单：我要两个汉堡、一杯饮料和薯条。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">输出：</span><br></span></code></pre></div></div>
<p><strong>响应：</strong></p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"hamburger"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"drink"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"fries"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>注意 <code>"cheeseburger"</code> 从输出中排除了，因为它不是订单的一部分。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="约束">约束<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E7%BA%A6%E6%9D%9F" class="hash-link" aria-label="约束的直接链接" title="约束的直接链接" translate="no">​</a></h3>
<p>指定阅读提示词或生成响应的任何约束。您可以告诉模型做什么和不做什么。例如，您可以在提示词中指定摘要长度的约束：</p>
<p><strong>提示词：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">用一句话总结这段文字：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">文字：量子计算机利用量子力学现象执行计算，速度比任何现代传统计算机快得多。在非常微小的尺度上，物质既表现为粒子又表现为波，量子计算使用专门的硬件来利用这种行为。量子设备的操作原理超出了经典物理学的范围。当大规模部署时，量子计算机可用于各种应用，例如：在网络安全中破解现有加密方法，同时帮助研究人员创建新方法；在气象学中开发更好的天气预报等。然而，当前最先进的量子计算机在很大程度上仍是实验性和不实用的。</span><br></span></code></pre></div></div>
<p><strong>响应：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">量子计算机利用量子力学现象，执行计算的速度比传统计算机快得多，可用于网络安全和气象学等潜在应用，尽管它们目前在很大程度上仍是实验性和不实用的。</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="响应格式">响应格式<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E5%93%8D%E5%BA%94%E6%A0%BC%E5%BC%8F" class="hash-link" aria-label="响应格式的直接链接" title="响应格式的直接链接" translate="no">​</a></h3>
<p>您可以给出指定响应格式的指令。例如，您可以要求响应格式化为表格、项目符号列表、电梯演讲、关键词、句子或段落。以下系统指令告诉模型在响应中更加对话化：</p>
<p><strong>系统指令：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">除非用户特别要求简洁的响应，否则所有问题都应详细全面地回答。</span><br></span></code></pre></div></div>
<p><strong>提示词：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">在 2025 年销售 DVD 的企业，有什么聪明的做法？</span><br></span></code></pre></div></div>
<p><strong>响应：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">由于数字流媒体和点播服务的压倒性主导地位，在 2025 年开始销售 DVD 的业务面临着重大挑战；因此，“聪明”的方法需要高度专业化的利基市场、超越光盘本身的强大价值主张，以及可能专注于社区或收藏家市场而不是主流消费。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">以下是 2025 年聪明的 DVD 业务可能包含的内容：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">1. 极端利基专业化：您无法与流媒体库竞争。您的业务必须专注于数字不容易或根本不提供的内容。这可能包括：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   * 绝版和稀有标题：寻找从未以数字方式发行或目前在主要流媒体平台上无法获得的电影或电视节目。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   ....</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="使用完成策略格式化响应">使用完成策略格式化响应<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E4%BD%BF%E7%94%A8%E5%AE%8C%E6%88%90%E7%AD%96%E7%95%A5%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%93%8D%E5%BA%94" class="hash-link" aria-label="使用完成策略格式化响应的直接链接" title="使用完成策略格式化响应的直接链接" translate="no">​</a></h4>
<p><a href="https://ai.google.dev/gemini-api/docs/prompting-strategies#completion" target="_blank" rel="noopener noreferrer" class="">完成策略</a>也可以帮助格式化响应。以下示例提示模型创建论文大纲：</p>
<p><strong>提示词：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">创建一篇关于蜂鸟的论文大纲。</span><br></span></code></pre></div></div>
<p><strong>响应：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">以下是关于蜂鸟的论文可能的大纲：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">I. 引言</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   A. 钩子：以关于蜂鸟的引人入胜的事实或描述开始（例如，它们的速度、彩虹色或微小的尺寸）。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   B. 背景：简要介绍蜂鸟——它们的分布（美洲）、它们作为独特鸟类的声誉。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   C. 论点陈述：陈述论文的主要观点，可以是关于蜂鸟的显著适应性、行为和生态重要性。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">II. 外观和识别</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   .....</span><br></span></code></pre></div></div>
<p>提示词没有指定大纲的格式，模型为您选择了一种格式。要让模型返回特定格式的大纲，您可以添加代表大纲开始的文本，让模型根据您发起的模式完成它。</p>
<p><strong>提示词：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">创建一篇关于蜂鸟的论文大纲。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">I. 引言</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   *</span><br></span></code></pre></div></div>
<p><strong>响应：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">好的，这是关于蜂鸟的论文大纲，从您提供的引言开始：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">I. 引言</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   * 钩子：以关于蜂鸟的引人入胜的事实或描述开始（例如，它们的速度、彩虹色或微小的尺寸）。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   * 背景：简要介绍蜂鸟——它们的分布（美洲）、它们作为独特鸟类的声誉及其一般特征。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   * 论点陈述：陈述论文的主要观点，重点关注使蜂鸟非凡的显著适应性、行为和生态意义。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   .....</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="零样本与少样本提示词">零样本与少样本提示词<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E9%9B%B6%E6%A0%B7%E6%9C%AC%E4%B8%8E%E5%B0%91%E6%A0%B7%E6%9C%AC%E6%8F%90%E7%A4%BA%E8%AF%8D" class="hash-link" aria-label="零样本与少样本提示词的直接链接" title="零样本与少样本提示词的直接链接" translate="no">​</a></h2>
<p>您可以在提示词中包含示例，向模型展示正确的做法。模型尝试从示例中识别模式和关系，并在生成响应时应用它们。包含少量示例的提示词称为<strong>少样本</strong>提示词，而不提供示例的提示词称为<strong>零样本</strong>提示词。少样本提示词通常用于规范格式、措辞、范围或模型响应的一般模式。使用具体且多样化的示例帮助模型缩小焦点并生成更准确的结果。</p>
<p>我们建议始终在提示词中包含少样本示例。没有少样本示例的提示词可能效果较差。实际上，如果您的示例在显示手头任务方面足够清晰，您可以从提示词中删除指令。</p>
<p>以下零样本提示词要求模型选择最佳解释。</p>
<p><strong>提示词：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">请选择问题的最佳解释：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">问题：雪是如何形成的？</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">解释 1：雪是在空气中的水蒸气在大气中冻结成冰晶时形成的，这些冰晶可以在大气中下降时结合并生长成雪花，并在地面上积累。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">解释 2：水蒸气冻结成冰晶形成雪。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">答案：</span><br></span></code></pre></div></div>
<p><strong>响应：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">解释 1 是更好的解释，因为它提供了关于该过程的更多细节，包括冰晶如何在大气中下降时结合并生长成雪花。</span><br></span></code></pre></div></div>
<p>如果您的用例要求模型产生简洁的响应，您可以在提示词中包含偏好简洁响应的示例。</p>
<p>以下提示词提供了两个显示偏好较短解释的示例。在响应中，您可以看到示例引导模型选择较短的解释（<code>解释 2</code>），而不是像之前那样选择较长的解释（<code>解释 1</code>）。</p>
<p><strong>提示词：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">以下是一些显示问题、解释和答案格式的示例：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">问题：为什么天空是蓝色的？</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">解释 1：天空看起来是蓝色的，因为瑞利散射，这导致较短的蓝色波长的光比较长的红色波长更容易散射，使天空看起来是蓝色的。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">解释 2：由于瑞利散射效应。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">答案：解释 2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">问题：地震的原因是什么？</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">解释 1：地壳中能量的突然释放。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">解释 2：当构造板块突然滑动或断裂时会发生地震，导致能量释放，产生地震波，可以震动地面并造成损坏。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">答案：解释 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">现在，根据上面的示例格式回答以下问题：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">问题：雪是如何形成的？</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">解释 1：雪是在空气中的水蒸气在大气中冻结成冰晶时形成的，这些冰晶可以在大气中下降时结合并生长成雪花，并在地面上积累。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">解释 2：水蒸气冻结成冰晶形成雪。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">答案：</span><br></span></code></pre></div></div>
<p><strong>响应：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">答案：解释 2</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="最佳示例数量">最佳示例数量<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E6%9C%80%E4%BD%B3%E7%A4%BA%E4%BE%8B%E6%95%B0%E9%87%8F" class="hash-link" aria-label="最佳示例数量的直接链接" title="最佳示例数量的直接链接" translate="no">​</a></h3>
<p>像 Gemini 这样的模型通常可以使用少量示例识别模式，尽管您可能需要尝试在提示词中提供的示例数量以获得最佳结果。同时，如果您包含太多示例，模型可能会开始对示例的响应<a href="https://developers.google.com/machine-learning/glossary#overfitting" target="_blank" rel="noopener noreferrer" class="">过度拟合</a>。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="模式与反模式">模式与反模式<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E6%A8%A1%E5%BC%8F%E4%B8%8E%E5%8F%8D%E6%A8%A1%E5%BC%8F" class="hash-link" aria-label="模式与反模式的直接链接" title="模式与反模式的直接链接" translate="no">​</a></h3>
<p>使用示例向模型展示要遵循的模式比使用示例向模型展示要避免的反模式更有效。</p>
<p><strong>❌ 负面模式：</strong></p>
<p><strong>示例：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">不要以问题结束俳句：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">俳句很有趣</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">一首简短而简单的诗</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">你不喜欢它们吗？</span><br></span></code></pre></div></div>
<p><strong>✅ 正面模式：</strong></p>
<p><strong>示例：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">始终以断言结束俳句：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">俳句很有趣</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">一首简短而简单的诗</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">写作的乐趣</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="一致的格式">一致的格式<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E4%B8%80%E8%87%B4%E7%9A%84%E6%A0%BC%E5%BC%8F" class="hash-link" aria-label="一致的格式的直接链接" title="一致的格式的直接链接" translate="no">​</a></h3>
<p>确保少样本示例的结构和格式相同，以避免产生不良格式的响应。在提示词中添加少样本示例的主要目标之一是向模型展示响应格式。因此，确保所有示例的格式一致至关重要，特别要注意 XML 标签、空格、换行符和示例分隔符。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="添加上下文">添加上下文<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E6%B7%BB%E5%8A%A0%E4%B8%8A%E4%B8%8B%E6%96%87" class="hash-link" aria-label="添加上下文的直接链接" title="添加上下文的直接链接" translate="no">​</a></h2>
<p>您可以在提示词中包含模型解决问题所需的指令和信息，而不是假设模型拥有所有必需的信息。这种上下文信息有助于模型理解您要求它做什么的约束和细节。</p>
<p>以下示例要求模型提供路由器的故障排除指导：</p>
<p><strong>提示词：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">我应该怎么做才能修复断开的 WiFi？</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">我的 Google WiFi 路由器上的灯是黄色的，缓慢闪烁。</span><br></span></code></pre></div></div>
<p><strong>响应：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Google WiFi 路由器上的黄色闪烁灯通常表示互联网连接有问题。以下是一些故障排除和修复问题的步骤：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">1. 重启路由器和调制解调器：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   - 从电源插座拔下调制解调器，等待 30 秒。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   - 将调制解调器重新插入，等待它完全启动。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   - 拔下 Google WiFi 路由器，等待 30 秒。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   - 将 Google WiFi 路由器重新插入，等待它完全启动。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   .....</span><br></span></code></pre></div></div>
<p>响应看起来像通用的故障排除信息，不特定于路由器或 LED 指示灯的状态。</p>
<p>要为特定路由器定制响应，您可以在提示词中添加路由器的故障排除指南作为上下文，供其在提供响应时参考。</p>
<p><strong>提示词：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">使用下面的文本回答问题。仅使用提供的文本进行响应。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">问题：我应该怎么做才能修复断开的 WiFi？我的 Google WiFi 路由器上的灯是黄色的，缓慢闪烁。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">文本：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">颜色：缓慢脉动黄色</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">含义：存在网络错误。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">处理方法：检查以太网电缆是否连接到路由器和调制解调器，并且两个设备都已打开。您可能需要重新拔插每个设备。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">颜色：快速闪烁黄色</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">含义：您正在按住重置按钮并进行出厂重置。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">处理方法：如果您继续按住重置按钮，大约 12 秒后，灯将变为稳定黄色。一旦变为稳定黄色，松开出厂重置按钮。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">颜色：稳定黄色</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">含义：路由器正在进行出厂重置。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">处理方法：这可能需要长达 10 分钟。完成后，设备将重置并开始脉动白色，让您知道它已准备好进行设置。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">颜色：稳定红色</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">含义：出现问题。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">处理方法：严重故障。出厂重置路由器。如果灯保持红色，请联系 WiFi 客户支持。</span><br></span></code></pre></div></div>
<p><strong>响应：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">检查以太网电缆是否连接到路由器和调制解调器，并且两个设备都已打开。您可能需要重新拔插每个设备。</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="添加前缀">添加前缀<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E6%B7%BB%E5%8A%A0%E5%89%8D%E7%BC%80" class="hash-link" aria-label="添加前缀的直接链接" title="添加前缀的直接链接" translate="no">​</a></h2>
<p>前缀是您添加到提示词内容的单词或短语，可以根据您放置前缀的位置发挥多种作用：</p>
<ul>
<li class=""><strong>输入前缀:</strong> 在输入中添加前缀向模型发出输入语义上有意义的部分的信号。例如，前缀 <code>English:</code> 和 <code>French:</code> 界定两种不同的语言。</li>
<li class=""><strong>输出前缀:</strong> 即使输出是由模型生成的，您也可以在提示词中为输出添加前缀。输出前缀为模型提供有关预期响应的信息。例如，输出前缀 <code>JSON:</code> 向模型发出信号，表明输出应为 JSON 格式。</li>
<li class=""><strong>示例前缀:</strong> 在少样本提示词中，向示例添加前缀提供标签，模型可以在生成输出时使用这些标签，这使得解析输出内容更容易。</li>
</ul>
<p>在以下示例中，<code>Text:</code>是输入前缀，<code>The answer is:</code>是输出前缀。</p>
<p><strong>提示词：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">将文本分类为以下类别之一。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">- large（大型）</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">- small（小型）</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Text: Rhino</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">The answer is: large</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Text: Mouse</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">The answer is: small</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Text: Snail</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">The answer is: small</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Text: Elephant</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">The answer is:</span><br></span></code></pre></div></div>
<p><strong>响应：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">The answer is: large</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="将提示词分解为组件">将提示词分解为组件<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E5%B0%86%E6%8F%90%E7%A4%BA%E8%AF%8D%E5%88%86%E8%A7%A3%E4%B8%BA%E7%BB%84%E4%BB%B6" class="hash-link" aria-label="将提示词分解为组件的直接链接" title="将提示词分解为组件的直接链接" translate="no">​</a></h2>
<p>对于需要复杂提示词的用例，您可以通过将事物分解为更简单的组件来帮助模型管理这种复杂性。</p>
<ol>
<li class="">
<p><strong>分解指令:</strong> 不要在一个提示词中包含许多指令，而是为每个指令创建一个提示词。您可以根据用户的输入选择要处理的提示词。</p>
</li>
<li class="">
<p><strong>链接提示词:</strong> 对于涉及多个顺序步骤的复杂任务，将每个步骤作为一个提示词，并按顺序链接提示词。在这个顺序链中，序列中一个提示词的输出成为下一个提示词的输入。序列中最后一个提示词的输出是最终输出。</p>
</li>
<li class="">
<p><strong>聚合响应:</strong> 聚合是指您想对数据的不同部分执行不同的并行任务，并聚合结果以产生最终输出。例如，您可以告诉模型对数据的第一部分执行一项操作，对其余数据执行另一项操作并聚合结果。</p>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="尝试模型参数">尝试模型参数<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E5%B0%9D%E8%AF%95%E6%A8%A1%E5%9E%8B%E5%8F%82%E6%95%B0" class="hash-link" aria-label="尝试模型参数的直接链接" title="尝试模型参数的直接链接" translate="no">​</a></h2>
<p>您发送到模型的每个调用都包含控制模型如何生成响应的参数值。模型可以为不同的参数值生成不同的结果。尝试不同的参数值以获得任务的最佳值。不同模型可用的参数可能不同。最常见的参数如下：</p>
<ol>
<li class="">
<p><strong>最大输出令牌数:</strong> 指定响应中可以生成的最大令牌数。一个令牌大约是四个字符。100 个令牌大约对应 60-80 个单词。</p>
</li>
<li class="">
<p><strong>温度:</strong> 温度控制令牌选择中的随机性程度。温度用于响应生成期间的采样，当应用 <code>topP</code> 和 <code>topK</code> 时发生。较低的温度适用于需要更确定性或更少开放式响应的提示词，而较高的温度可以导致更多样化或更有创意的结果。温度为 0 是确定性的，意味着始终选择最高概率的响应。</p>
<blockquote>
<p><strong>注意:</strong> 使用 Gemini 3 模型时，我们强烈建议将 <code>temperature</code> 保持在默认值 1.0。更改温度（将其设置为 1.0 以下）可能会导致意外行为，例如循环或性能下降，特别是在复杂的数学或推理任务中。</p>
</blockquote>
</li>
<li class="">
<p><strong><code>topK</code>:</strong> <code>topK</code> 参数改变模型如何选择令牌进行输出。<code>topK</code> 为 1 意味着所选令牌是模型词汇表中所有令牌中最可能的（也称为贪婪解码），而 <code>topK</code> 为 3 意味着使用温度从 3 个最可能的令牌中选择下一个令牌。对于每个令牌选择步骤，对具有最高概率的 <code>topK</code> 令牌进行采样。然后根据 <code>topP</code> 进一步过滤令牌，最后使用温度采样选择最终令牌。</p>
</li>
<li class="">
<p><strong><code>topP</code>:</strong> <code>topP</code> 参数改变模型如何选择令牌进行输出。从最可能到最不可能选择令牌，直到它们的概率之和等于 <code>topP</code> 值。例如，如果令牌 A、B 和 C 的概率分别为 0.3、0.2 和 0.1，<code>topP</code> 值为 0.5，则模型将使用温度选择 A 或 B 作为下一个令牌，并排除 C 作为候选。默认 <code>topP</code> 值为 0.95。</p>
</li>
<li class="">
<p><strong><code>stop_sequences</code>:</strong> 设置停止序列以告诉模型停止生成内容。停止序列可以是任何字符序列。尽量避免使用可能出现在生成内容中的字符序列。</p>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="提示词迭代策略">提示词迭代策略<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E6%8F%90%E7%A4%BA%E8%AF%8D%E8%BF%AD%E4%BB%A3%E7%AD%96%E7%95%A5" class="hash-link" aria-label="提示词迭代策略的直接链接" title="提示词迭代策略的直接链接" translate="no">​</a></h2>
<p>提示词设计有时需要进行几次迭代，然后才能持续获得您想要的响应。本节提供有关迭代提示词时可以尝试的一些事项的指导：</p>
<ol>
<li class="">
<p><strong>使用不同的措辞:</strong> 在提示词中使用不同的词或措辞通常会从模型中产生不同的响应，即使它们的意思相同。如果您没有从提示词中获得预期的结果，请尝试重新措辞。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">版本 1：我如何烤馅饼？</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">版本 2：建议一个馅饼的食谱。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">版本 3：有什么好的馅饼食谱？</span><br></span></code></pre></div></div>
</li>
<li class="">
<p><strong>切换到类似任务:</strong> 如果您无法让模型遵循任务的指令，请尝试为实现相同结果的类似任务提供指令。</p>
<p>此提示词告诉模型使用预定义类别对书籍进行分类：</p>
<p><strong>提示词：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">《奥德赛》属于哪个类别：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">惊悚片</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">科幻</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">神话</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">传记</span><br></span></code></pre></div></div>
<p><strong>响应：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">《奥德赛》属于**神话**类别。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">原因如下：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">* **神话:** 《奥德赛》讲述了奥德修斯的故事，他是希腊神话中的英雄，以及他在特洛伊战争后回家的旅程。它以希腊神话中常见的神、怪物和超自然事件为特色。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">.....</span><br></span></code></pre></div></div>
<p>响应是正确的，但模型没有保持在选项范围内。您还希望模型只用一个选项响应，而不是用完整的句子。在这种情况下，您可以将指令重新表述为多项选择题，并要求模型选择一个选项。</p>
<p><strong>提示词：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">多项选择题：以下哪个选项描述了《奥德赛》这本书？</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">选项：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">- 惊悚片</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">- 科幻</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">- 神话</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">- 传记</span><br></span></code></pre></div></div>
<p><strong>响应：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">正确答案是神话。</span><br></span></code></pre></div></div>
</li>
<li class="">
<p><strong>更改提示词内容的顺序:</strong> 提示词中内容的顺序有时会影响响应。尝试更改内容顺序，看看这如何影响响应。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">版本 1：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[示例]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[上下文]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[输入]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">版本 2：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[输入]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[示例]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[上下文]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">版本 3：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[示例]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[输入]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[上下文]</span><br></span></code></pre></div></div>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="后备响应">后备响应<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E5%90%8E%E5%A4%87%E5%93%8D%E5%BA%94" class="hash-link" aria-label="后备响应的直接链接" title="后备响应的直接链接" translate="no">​</a></h2>
<p>后备响应是当提示词或响应触发安全过滤器时模型返回的响应。后备响应的示例是 "我无法帮助解决这个问题，因为我只是一个语言模型。"</p>
<p>如果模型以后备响应响应，请尝试提高温度。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="要避免的事项">要避免的事项<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E8%A6%81%E9%81%BF%E5%85%8D%E7%9A%84%E4%BA%8B%E9%A1%B9" class="hash-link" aria-label="要避免的事项的直接链接" title="要避免的事项的直接链接" translate="no">​</a></h2>
<ul>
<li class="">避免依赖模型生成事实信息。</li>
<li class="">谨慎用于数学和逻辑问题。</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="gemini-3">Gemini 3<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#gemini-3" class="hash-link" aria-label="Gemini 3的直接链接" title="Gemini 3的直接链接" translate="no">​</a></h2>
<p>Gemini 3 模型专为高级推理和指令遵循而设计。它们对直接、结构良好并清楚定义任务和任何约束的提示词反应最佳。对于 Gemini 3 的最佳结果，建议采用以下做法：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="核心提示词原则">核心提示词原则<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E6%A0%B8%E5%BF%83%E6%8F%90%E7%A4%BA%E8%AF%8D%E5%8E%9F%E5%88%99" class="hash-link" aria-label="核心提示词原则的直接链接" title="核心提示词原则的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><strong>精确直接:</strong> 清晰简洁地陈述您的目标。避免不必要或过度说服性的语言。</li>
<li class=""><strong>使用一致的结构:</strong> 使用清晰的分隔符来分隔提示词的不同部分。XML 样式标签（例如 <code>&lt;context&gt;</code>、<code>&lt;task&gt;</code>）或 Markdown 标题是有效的。在单个提示词中选择一种格式并始终如一地使用它。</li>
<li class=""><strong>定义参数:</strong> 明确解释任何模糊的术语或参数。</li>
<li class=""><strong>控制输出详细程度:</strong> 默认情况下，Gemini 3 提供直接有效的答案。如果您需要更对话化或详细的响应，您必须在指令中明确请求。</li>
<li class=""><strong>连贯处理多模态输入:</strong> 使用文本、图像、音频或视频时，将它们视为同等级别的输入。确保您的指令根据需要清楚地引用每种模态。</li>
<li class=""><strong>优先考虑关键指令:</strong> 将基本行为约束、角色定义（角色）和输出格式要求放在系统指令或用户提示词的最开始。</li>
<li class=""><strong>为长上下文构建结构:</strong> 提供大量上下文（例如文档、代码）时，首先提供所有上下文。将您的具体指令或问题放在提示词的<strong>最后</strong>。</li>
<li class=""><strong>锚定上下文:</strong> 在大块数据之后，使用清晰的过渡短语来连接上下文和您的查询，例如 "基于以上信息..."</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="增强推理和规划">增强推理和规划<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E5%A2%9E%E5%BC%BA%E6%8E%A8%E7%90%86%E5%92%8C%E8%A7%84%E5%88%92" class="hash-link" aria-label="增强推理和规划的直接链接" title="增强推理和规划的直接链接" translate="no">​</a></h3>
<p>您可以利用 Gemini 3 的高级思维能力，通过提示它在提供最终响应之前进行规划或自我批评来提高复杂任务的响应质量。</p>
<p><strong>示例 - 明确规划：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">在提供最终答案之前，请：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">1. 将既定目标解析为不同的子任务。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">2. 检查输入信息是否完整。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">3. 创建结构化大纲以实现目标。</span><br></span></code></pre></div></div>
<p><strong>示例 - 自我批评：</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">在返回最终响应之前，请根据用户的原始约束检查您生成的输出。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">1. 我是否回答了用户的*意图*，而不仅仅是他们的字面意思？</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">2. 语气是否符合所要求的角色？</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="结构化提示词示例">结构化提示词示例<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E7%BB%93%E6%9E%84%E5%8C%96%E6%8F%90%E7%A4%BA%E8%AF%8D%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="结构化提示词示例的直接链接" title="结构化提示词示例的直接链接" translate="no">​</a></h3>
<p>使用标签或 Markdown 可帮助模型区分指令、上下文和任务。</p>
<p><strong>XML 示例：</strong></p>
<div class="language-xml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-xml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">role</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">您是一个有用的助手。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">role</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">constraints</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">1. 保持客观。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">2. 引用来源。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">constraints</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">context</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[在此处插入用户输入 - 模型知道这是数据，而非指令]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">context</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">task</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[在此处插入具体的用户请求]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">task</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<p><strong>Markdown 示例：</strong></p>
<div class="language-markdown codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-markdown codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token title important punctuation" style="color:#393A34">#</span><span class="token title important"> 身份</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">您是一名高级解决方案架构师。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token title important punctuation" style="color:#393A34">#</span><span class="token title important"> 约束</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token list punctuation" style="color:#393A34">-</span><span class="token plain"> 不允许使用外部库。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token list punctuation" style="color:#393A34">-</span><span class="token plain"> 仅使用 Python 3.11+ 语法。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token title important punctuation" style="color:#393A34">#</span><span class="token title important"> 输出格式</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">返回单个代码块。</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="结合最佳实践的示例模板">结合最佳实践的示例模板<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E7%BB%93%E5%90%88%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%E7%9A%84%E7%A4%BA%E4%BE%8B%E6%A8%A1%E6%9D%BF" class="hash-link" aria-label="结合最佳实践的示例模板的直接链接" title="结合最佳实践的示例模板的直接链接" translate="no">​</a></h3>
<p>此模板捕获了使用 Gemini 3 进行提示的核心原则。请务必根据您的具体用例进行迭代和修改。</p>
<p><strong>系统指令：</strong></p>
<div class="language-xml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-xml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">role</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">您是 Gemini 3，[插入领域，例如数据科学]的专业助手。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">您精确、分析性强且坚持不懈。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">role</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">instructions</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">1. **规划**：分析任务并创建分步计划。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">2. **执行**：执行计划。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">3. **验证**：根据用户的任务检查您的输出。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">4. **格式化**：以请求的结构呈现最终答案。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">instructions</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">constraints</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">- 详细程度：[指定 低/中/高]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">- 语气：[指定 正式/随意/技术性]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">constraints</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">output_format</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">按如下方式构建您的响应：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">1. **执行摘要**：[简短概述]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">2. **详细响应**：[主要内容]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">output_format</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<p><strong>用户提示词：</strong></p>
<div class="language-xml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-xml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">context</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[在此处插入相关文档、代码片段或背景信息]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">context</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">task</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[在此处插入具体的用户请求]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">task</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">final_instruction</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">记住在回答之前要逐步思考。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">final_instruction</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="代理工作流">代理工作流<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E4%BB%A3%E7%90%86%E5%B7%A5%E4%BD%9C%E6%B5%81" class="hash-link" aria-label="代理工作流的直接链接" title="代理工作流的直接链接" translate="no">​</a></h2>
<p>对于深度代理工作流，通常需要特定的指令来控制模型如何推理、规划和执行任务。虽然 Gemini 提供了强大的通用性能，但复杂的代理通常需要您配置计算成本（延迟和令牌）与任务准确性之间的权衡。</p>
<p>在为代理设计提示词时，请考虑您可以在代理中引导的以下行为维度：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="推理和策略">推理和策略<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E6%8E%A8%E7%90%86%E5%92%8C%E7%AD%96%E7%95%A5" class="hash-link" aria-label="推理和策略的直接链接" title="推理和策略的直接链接" translate="no">​</a></h3>
<p>配置模型在采取行动之前如何思考和规划。</p>
<ul>
<li class=""><strong>逻辑分解:</strong> 定义模型必须多彻底地分析约束、先决条件和操作顺序。</li>
<li class=""><strong>问题诊断:</strong> 控制识别原因时的分析深度以及模型对溯因推理的使用。确定模型是应该接受最明显的答案还是探索复杂、不太可能的解释。</li>
<li class=""><strong>信息详尽性:</strong> 在分析每个可用策略和文档与优先考虑效率和速度之间进行权衡。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="执行和可靠性">执行和可靠性<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E6%89%A7%E8%A1%8C%E5%92%8C%E5%8F%AF%E9%9D%A0%E6%80%A7" class="hash-link" aria-label="执行和可靠性的直接链接" title="执行和可靠性的直接链接" translate="no">​</a></h3>
<p>配置代理如何自主操作和处理障碍。</p>
<ul>
<li class=""><strong>适应性:</strong> 模型如何对新数据做出反应。确定它是应该严格遵守其初始计划，还是在观察结果与假设相矛盾时立即转向。</li>
<li class=""><strong>持久性和恢复:</strong> 模型尝试自我纠正错误的程度。高持久性会提高成功率，但会面临更高的令牌成本或循环风险。</li>
<li class=""><strong>风险评估:</strong> 评估后果的逻辑。明确区分低风险的探索性操作（读取）和高风险的状态更改（写入）。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="交互和输出">交互和输出<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E4%BA%A4%E4%BA%92%E5%92%8C%E8%BE%93%E5%87%BA" class="hash-link" aria-label="交互和输出的直接链接" title="交互和输出的直接链接" translate="no">​</a></h3>
<p>配置代理如何与用户通信和格式化结果。</p>
<ul>
<li class=""><strong>歧义和权限处理:</strong> 定义何时允许模型做出假设，何时必须暂停执行以请求用户澄清或许可。</li>
<li class=""><strong>详细程度:</strong> 控制与工具调用一起生成的文本量。这决定了模型是向用户解释其操作还是在执行期间保持沉默。</li>
<li class=""><strong>精确性和完整性:</strong> 输出所需的保真度。指定模型是否必须解决每个边缘情况并提供确切数字，或者大致估计是否可以接受。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="系统指令模板">系统指令模板<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E7%B3%BB%E7%BB%9F%E6%8C%87%E4%BB%A4%E6%A8%A1%E6%9D%BF" class="hash-link" aria-label="系统指令模板的直接链接" title="系统指令模板的直接链接" translate="no">​</a></h3>
<p>以下系统指令是一个示例，已经过研究人员评估，可以提高代理基准测试的性能，在这些基准测试中，模型必须遵守复杂的规则手册并与用户互动。它鼓励代理充当强大的推理者和规划者，在上述维度上强制执行特定行为，并要求模型在采取任何行动之前主动规划。</p>
<p>您可以调整此模板以适应您的特定用例约束。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">您是一个非常强大的推理者和规划者。使用这些关键指令来构建您的计划、思想和响应。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">在采取任何行动（工具调用*或*对用户的响应）之前，您必须主动、系统地、独立地规划和推理：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">1) 逻辑依赖关系和约束：根据以下因素分析预期操作。按重要性顺序解决冲突：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    1.1) 基于策略的规则、强制性先决条件和约束。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    1.2) 操作顺序：确保采取操作不会阻止后续必要的操作。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        1.2.1) 用户可能以随机顺序请求操作，但您可能需要重新排序操作以最大化任务的成功完成。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    1.3) 其他先决条件（所需的信息和/或操作）。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    1.4) 明确的用户约束或偏好。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">2) 风险评估：采取该操作的后果是什么？新状态会导致任何未来问题吗？</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    2.1) 对于探索性任务（如搜索），缺少*可选*参数是低风险。**除非**您的`规则 1`（逻辑依赖关系）推理确定可选信息对于计划中的后续步骤是必需的，否则更倾向于使用可用信息调用工具，而不是询问用户。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">3) 溯因推理和假设探索：在每个步骤中，确定遇到的任何问题最合乎逻辑和最可能的原因。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    3.1) 超越直接或明显的原因。最可能的原因可能不是最简单的，可能需要更深入的推断。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    3.2) 假设可能需要额外的研究。每个假设可能需要多个步骤来测试。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    3.3) 根据可能性对假设进行优先排序，但不要过早地丢弃不太可能的假设。低概率事件仍可能是根本原因。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">4) 结果评估和适应性：先前的观察是否需要对您的计划进行任何更改？</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    4.1) 如果您的初始假设被证伪，请根据收集的信息主动生成新假设。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">5) 信息可用性：合并所有适用的和替代的信息来源，包括：</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    5.1) 使用可用工具及其功能</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    5.2) 所有策略、规则、检查清单和约束</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    5.3) 先前的观察和对话历史</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    5.4) 仅通过询问用户才能获得的信息</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">6) 精确性和基础：确保您的推理对每种确切的持续情况都极其精确和相关。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    6.1) 在引用信息时，通过引用确切的适用信息（包括策略）来验证您的声明。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">7) 完整性：确保所有要求、约束、选项和偏好都详尽地纳入您的计划。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    7.1) 使用 #1 中的重要性顺序解决冲突。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    7.2) 避免过早结论：给定情况可能有多个相关选项。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        7.2.1) 要检查选项是否相关，请推理 #5 中的所有信息来源。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        7.2.2) 您可能需要咨询用户才能知道某事是否适用。不要在不检查的情况下假设它不适用。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    7.3) 查看 #5 中的适用信息来源，以确认哪些与当前状态相关。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">8) 持久性和耐心：除非上述所有推理都已用尽，否则不要放弃。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    8.1) 不要因所花费的时间或用户沮丧而气馁。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    8.2) 这种持久性必须是智能的：对于*瞬态*错误（例如，请重试），您*必须*重试**除非已达到明确的重试限制（例如，最多 x 次尝试）**。如果达到这样的限制，您*必须*停止。对于*其他*错误，您必须更改策略或参数，而不是重复相同的失败调用。</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">9) 抑制您的响应：仅在完成上述所有推理后才采取行动。一旦您采取了行动，就无法收回。</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="生成模型的底层原理">生成模型的底层原理<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E7%94%9F%E6%88%90%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86" class="hash-link" aria-label="生成模型的底层原理的直接链接" title="生成模型的底层原理的直接链接" translate="no">​</a></h2>
<p>本节旨在回答这个问题 - <em><strong>生成模型的响应中是否存在随机性，还是它们是确定性的？</strong></em></p>
<p>简短的答案 - 两者都是。当您提示生成模型时，文本响应会分两个阶段生成。在第一阶段，生成模型处理输入提示词并生成可能接下来出现的令牌（单词）的<strong>概率分布</strong>。例如，如果您使用输入文本 "The dog jumped over the ..." 进行提示，生成模型将产生一系列可能的下一个单词：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[("fence", 0.77), ("ledge", 0.12), ("blanket", 0.03), ...]</span><br></span></code></pre></div></div>
<p>这个过程是确定性的；每次输入相同的提示文本时，生成模型都会产生相同的分布。</p>
<p>在第二阶段，生成模型通过几种解码策略之一将这些分布转换为实际的文本响应。一个简单的解码策略可能是在每个时间步选择最可能的令牌。这个过程总是确定性的。但是，您可以选择通过对模型返回的分布进行<em>随机采样</em>来生成响应。这个过程将是随机的（随机的）。通过设置温度来控制此解码过程中允许的随机性程度。温度为 0 意味着只选择最可能的令牌，并且没有随机性。相反，高温度会在模型选择的令牌中注入高度的随机性，从而导致更意外、更令人惊讶的模型响应。对于 <strong>Gemini 3</strong>，建议不要更改默认温度 1.0 以避免意外结果。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="后续步骤">后续步骤<a href="https://your-docusaurus-site.example.com/prompt-design-strategies#%E5%90%8E%E7%BB%AD%E6%AD%A5%E9%AA%A4" class="hash-link" aria-label="后续步骤的直接链接" title="后续步骤的直接链接" translate="no">​</a></h2>
<ul>
<li class="">既然您对提示词设计有了更深入的了解，请尝试使用 <a href="http://aistudio.google.com/" target="_blank" rel="noopener noreferrer" class="">Google AI Studio</a> 编写自己的提示词</li>
<li class="">了解有关 Gemini 3 Pro Preview 模型的更多信息</li>
<li class="">要了解多模态提示，请参阅<a href="https://ai.google.dev/gemini-api/docs/files#prompt-guide" target="_blank" rel="noopener noreferrer" class="">使用媒体文件进行提示</a>。</li>
<li class="">要了解图像提示，请参阅 <a href="https://ai.google.dev/gemini-api/docs/image-generation#imagen-prompt-guide" target="_blank" rel="noopener noreferrer" class="">Imagen 提示指南</a></li>
<li class="">要了解视频提示，请参阅 <a href="https://ai.google.dev/gemini-api/docs/video#prompt-guide" target="_blank" rel="noopener noreferrer" class="">Veo 提示指南</a></li>
</ul>]]></content>
        <author>
            <name>Claude</name>
            <uri>https://claude.ai</uri>
        </author>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="gemini" term="gemini"/>
        <category label="prompt" term="prompt"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[TypeScript：如何区分实例与结构相同的对象]]></title>
        <id>https://your-docusaurus-site.example.com/typescript-nominal-typing-with-private-members</id>
        <link href="https://your-docusaurus-site.example.com/typescript-nominal-typing-with-private-members"/>
        <updated>2025-11-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[以下内容均为 Gemini 2.5 Pro 生成]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>以下内容均为 <code>Gemini 2.5 Pro</code> 生成</p>
</blockquote>
<p>当你在 TypeScript 中定义一个类 (class) 并希望一个函数只接受该类的 <em>实例</em> 时，你可能会遇到一个令人困惑的情况。</p>
<p>假设你有以下代码：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">sayHello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">Hello, my name is </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation keyword" style="color:#00009f">this</span><span class="token template-string interpolation punctuation" style="color:#393A34">.</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Person</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">sayHello</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ✅ 没问题，这符合预期</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Alice"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ❓ 咦？为什么这也行？！</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Tom"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 错误: Property 'sayHello' is missing in type '{ name: string; }'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// but required in type 'Person'.</span><br></span></code></pre></div></div>
<p><em>（注：在上面的基础示例中，如果 <code>Person</code> 类有 <code>sayHello</code> 方法，那么 <code>{ name: "Tom" }</code> 会报错，因为它缺少该方法。但如果 <code>Person</code> 类<strong>只</strong>有 <code>name</code> 属性，代码就<strong>不会</strong>报错，这正是问题的核心。）</em></p>
<p>让我们用一个更简洁的例子来重现这个问题：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Person</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ✅ 传入实例</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Alice"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ❌ 为什么这里不报错？</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 我传入了一个对象字面量，而不是 Person 的实例！</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Tom"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>这到底是怎么回事？这其实是 TypeScript 的一个核心特性在起作用，它被称为 <strong>结构化类型（Structural Typing）</strong>，也常被称作“鸭子类型”。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="什么是结构化类型">什么是结构化类型？<a href="https://your-docusaurus-site.example.com/typescript-nominal-typing-with-private-members#%E4%BB%80%E4%B9%88%E6%98%AF%E7%BB%93%E6%9E%84%E5%8C%96%E7%B1%BB%E5%9E%8B" class="hash-link" aria-label="什么是结构化类型？的直接链接" title="什么是结构化类型？的直接链接" translate="no">​</a></h2>
<p>TypeScript 在比较类型时，并不关心“你叫什么名字”（即名义类型，Nominal Typing），而只关心“你长什么样”（即结构化类型，Structural Typing）。</p>
<p>在上面的例子中：</p>
<ol>
<li class="">函数 <code>get</code> 期望一个类型为 <code>Person</code> 的参数。</li>
<li class=""><code>Person</code> 类型的 <em>结构</em> 被定义为：<strong>“一个拥有 <code>string</code> 类型 <code>name</code> 属性的对象”</strong>。</li>
<li class="">我们传入的对象字面量 <code>{ name: "Tom" }</code>，它的 <em>结构</em> 也是：<strong>“一个拥有 <code>string</code> 类型 <code>name</code> 属性的对象”</strong>。</li>
</ol>
<p>由于两者结构兼容，TypeScript 编译器说：“看起来像一只鸭子，叫起来也像一只鸭子……那它就是一只鸭子。” 于是，编译通过了。</p>
<p>但这并不是我们想要的！我们希望 <code>get</code> 函数<strong>只接受</strong>通过 <code>new Person(...)</code> 创建的真实实例。那么，如何做到这一点呢？</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="解决方案使用私有品牌-private-branding">解决方案：使用“私有品牌” (Private Branding)<a href="https://your-docusaurus-site.example.com/typescript-nominal-typing-with-private-members#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E4%BD%BF%E7%94%A8%E7%A7%81%E6%9C%89%E5%93%81%E7%89%8C-private-branding" class="hash-link" aria-label="解决方案：使用“私有品牌” (Private Branding)的直接链接" title="解决方案：使用“私有品牌” (Private Branding)的直接链接" translate="no">​</a></h2>
<p>要强制实现名义类型（即严格限制为类的实例），最简单、最常用的技巧是给类添加一个<strong>私有成员</strong>。</p>
<p>这个私有成员就像一个独一无二的“品牌”标记，只有这个类和它的实例才能拥有。</p>
<p>让我们来修改 <code>Person</code> 类：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 👇 **这就是关键！**</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 我们添加了一个私有的 "品牌" 属性</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> _brand</span><span class="token operator" style="color:#393A34">!</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Person</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ✅ 正确：传入 Person 的实例</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Alice"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ❌ 错误：传入对象字面量</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Tom"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>现在，当你尝试传入对象字面量时，TypeScript 编译器会立刻报错：</p>
<blockquote>
<p>Argument of type <code>{ name: string; }</code> is not assignable to parameter of type <code>Person</code>.
<strong>Property <code>_brand</code> is missing</strong> in type <code>{ name: string; }</code> but required in type <code>Person</code>.</p>
</blockquote>
<p><strong>为什么这样能行？</strong></p>
<ul>
<li class=""><code>new Person("Alice")</code> 创建的实例，其类型签名中<strong>包含</strong> <code>private _brand: void</code>。</li>
<li class=""><code>{ name: "Tom" }</code> 这个对象字面量，其类型签名中<strong>不包含</strong> <code>_brand</code> 属性。</li>
</ul>
<p>因为 <code>private</code> 成员是类结构签名的一部分，而对象字面量无法提供这个私有成员，所以 TypeScript 判定它们的结构不兼容，从而达到了我们的目的。</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="零运行时成本的幽灵属性">零运行时成本的“幽灵属性”<a href="https://your-docusaurus-site.example.com/typescript-nominal-typing-with-private-members#%E9%9B%B6%E8%BF%90%E8%A1%8C%E6%97%B6%E6%88%90%E6%9C%AC%E7%9A%84%E5%B9%BD%E7%81%B5%E5%B1%9E%E6%80%A7" class="hash-link" aria-label="零运行时成本的“幽灵属性”的直接链接" title="零运行时成本的“幽灵属性”的直接链接" translate="no">​</a></h2>
<p>你可能会问：“这个 <code>_brand</code> 属性会增加我运行时的开销吗？它会存在于我最终的 JavaScript 代码中吗？”</p>
<p><strong>答案是：完全不会。</strong></p>
<p>这正是这个技巧最巧妙的地方。让我们来分解这行代码：<code>private _brand!: void;</code></p>
<ol>
<li class=""><strong><code>private</code></strong>：这是一个 TypeScript 的访问修饰符。它<strong>只在编译时有效</strong>，用于类型检查。它会在编译成 JavaScript 时被<strong>完全擦除</strong>。</li>
<li class=""><strong><code>!</code></strong> (非空断言)：这是在告诉 TypeScript：“你不用担心这个属性没被初始化，相信我。” 它<strong>只在编译时有效</strong>，用于“安抚”编译器，同样会被<strong>完全擦除</strong>。</li>
<li class=""><strong><code>: void</code></strong>：这是一个<strong>纯粹的类型注解</strong>。和所有 TypeScript 中的类型（如 <code>:string</code>, <code>:number</code>）一样，它会被<strong>完全擦除</strong>。</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="编译对比">编译对比<a href="https://your-docusaurus-site.example.com/typescript-nominal-typing-with-private-members#%E7%BC%96%E8%AF%91%E5%AF%B9%E6%AF%94" class="hash-link" aria-label="编译对比的直接链接" title="编译对比的直接链接" translate="no">​</a></h3>
<p><strong>你的 TypeScript (TS)</strong></p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> _brand</span><span class="token operator" style="color:#393A34">!</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p><strong>编译后的 JavaScript (JS)</strong></p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Person</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">constructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 注意：_brand 在这里完全消失了！</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p><code>_brand</code> 只是一个“幽灵属性”，它只存在于 TypeScript 的类型系统中，专门用来在编译时“品牌化”你的类。它对运行时的性能和内存占用<strong>没有任何影响</strong>。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://your-docusaurus-site.example.com/typescript-nominal-typing-with-private-members#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><strong>问题</strong>：TypeScript 默认使用<strong>结构化类型</strong>，导致对象字面量可以匹配同结构的类。</li>
<li class=""><strong>目标</strong>：我们想强制使用<strong>名义类型</strong>，只接受类的真实实例。</li>
<li class=""><strong>解决方案</strong>：在类中添加一个 <code>private</code> 属性（如 <code>private _brand!: void;</code>）来进行“品牌化”。</li>
<li class=""><strong>优势</strong>：此方法<strong>零运行时成本</strong>，所有“品牌”标记都在编译为 JavaScript 时被擦除，只在 TypeScript 类型检查阶段发挥作用。</li>
</ul>
<p>下次当你需要确保一个参数必须是某个类的实例时，试试这个“私有品牌”技巧吧！</p>]]></content>
        <author>
            <name>Gemini</name>
            <uri>https://gemini.google.com</uri>
        </author>
        <category label="typescript" term="typescript"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Clash TUN 模式的兔子洞：一次从 DNS 到 UDP 的排错之旅]]></title>
        <id>https://your-docusaurus-site.example.com/troubleshooting-clash-tun-mode</id>
        <link href="https://your-docusaurus-site.example.com/troubleshooting-clash-tun-mode"/>
        <updated>2025-10-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[以下内容均为 Gemini 2.5 Pro Deep Research 生成]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>以下内容均为 <code>Gemini 2.5 Pro Deep Research</code> 生成</p>
</blockquote>
<p>如果你是一位 Clash 的进阶用户，你很可能遇到过这个经典难题：一套精心编写、在"规则模式"（系统代理）下完美运行的规则，在切换到功能强大的"TUN 模式"后却突然失效。本该走向代理的流量莫名其妙地选择了直连,让你只能盯着连接日志，对自己的配置产生怀疑。</p>
<p>这正是一次此类排错之旅的真实记录——一个多层次的问题，它始于 DNS，意外地转向了网络协议，最终以一个优雅的脚本方案画上句号。跟随本文，你将理解其背后深层的运行机制，并学会如何彻底征服 TUN 模式。</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第一部分消失的主机名悬案">第一部分：消失的主机名悬案<a href="https://your-docusaurus-site.example.com/troubleshooting-clash-tun-mode#%E7%AC%AC%E4%B8%80%E9%83%A8%E5%88%86%E6%B6%88%E5%A4%B1%E7%9A%84%E4%B8%BB%E6%9C%BA%E5%90%8D%E6%82%AC%E6%A1%88" class="hash-link" aria-label="第一部分：消失的主机名悬案的直接链接" title="第一部分：消失的主机名悬案的直接链接" translate="no">​</a></h2>
<p>最初的问题非常明确。一位用户使用全局扩展脚本，在规则列表的顶端插入规则，以确保像 <code>claude.ai</code> 和 <code>claude.com</code> 这样的域名总是通过特定的代理分组。</p>
<p><strong>脚本如下：</strong></p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">config</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> profileName</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'proxy-groups'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">?.</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">rules</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">unshift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">DOMAIN-SUFFIX,claude.ai,</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">rules</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">unshift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">DOMAIN-SUFFIX,claude.com,</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>在 <strong>规则模式</strong> 下，一切正常。但在 <strong>TUN 模式</strong> 下，访问 Claude 的连接却走向了 <code>DIRECT</code>。</p>
<p><strong>根本原因：架构的鸿沟</strong></p>
<p>这是关于 TUN 模式的第一个，也是最基础的教训：它在网络堆栈的不同层级上工作。</p>
<ul>
<li class="">
<p><strong>规则模式 (系统代理):</strong> 工作在应用层。你的浏览器知道它正在与一个代理服务器对话，并发送一个明确包含主机名（例如 <code>claude.ai</code>）的 <code>HTTP CONNECT</code> 请求。Clash 直接就拿到了主机名。</p>
</li>
<li class="">
<p><strong>TUN 模式 (虚拟网卡):</strong> 工作在网络层。它拦截的是原始的 IP 数据包。当一个应用程序发送数据包时，它已经通过 DNS 将 <code>claude.ai</code> 解析成了一个真实的 IP 地址。Clash 的 TUN 接口只能看到目标 IP，而看不到原始的主机名。</p>
</li>
</ul>
<p>没有主机名，任何 <code>DOMAIN-SUFFIX</code> 规则都形同虚设。</p>
<p><strong>解决方案：<code>fake-ip</code> 登场</strong></p>
<p>这正是 Clash 的 <code>fake-ip</code> DNS 模式要解决的问题。启用后，Clash 会劫持所有的 DNS 请求。它不会返回真实的 IP，而是返回一个本地范围内的"假 IP"（例如 <code>198.18.0.1/16</code>），并在内部创建一个映射关系：<code>假 IP &lt;-&gt; 真实主机名</code>。</p>
<p>当 TUN 接口看到一个发往该假 IP 的数据包时，它会查询这个映射，恢复原始主机名，从而让基于域名的规则能够正确处理。</p>
<p><strong>用户的配置失误</strong></p>
<p>该用户启用了 <code>fake-ip</code>，但问题依旧。罪魁祸首隐藏在他的 DNS 设置中：他使用了 <code>fake-ip-filter-mode: blacklist</code>（黑名单模式）。这意味着任何匹配 <code>fake-ip-filter</code> 列表的域名都<strong>不会</strong>被分配假 IP。他的过滤器很可能包含了一个宽泛的规则集（如 <code>geosite:cn</code>），不经意间将 <code>claude.ai</code> 也纳入其中，导致它被解析为真实 IP，破坏了后续的规则匹配。</p>
<p>在调整了 DNS 过滤器后，我们取得了进展。连接日志现在可以正确显示主机名了。</p>
<p>问题解决了吗？还没有。流量<strong>仍然</strong>在走 <code>DIRECT</code>。</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第二部分意想不到的-udp-转折">第二部分：意想不到的 UDP 转折<a href="https://your-docusaurus-site.example.com/troubleshooting-clash-tun-mode#%E7%AC%AC%E4%BA%8C%E9%83%A8%E5%88%86%E6%84%8F%E6%83%B3%E4%B8%8D%E5%88%B0%E7%9A%84-udp-%E8%BD%AC%E6%8A%98" class="hash-link" aria-label="第二部分：意想不到的 UDP 转折的直接链接" title="第二部分：意想不到的 UDP 转折的直接链接" translate="no">​</a></h2>
<p>既然主机名已经正确识别，为什么规则还是不起作用？新的截图在"类型"一栏中给出了关键线索：<strong><code>Tun(udp)</code></strong>。</p>
<p><strong>根本原因：QUIC 协议 (HTTP/3)</strong></p>
<p>这揭示了两种模式之间第二个，也是更微妙的区别。</p>
<ul>
<li class="">
<p>在 <strong>规则模式</strong> 下，浏览器被强制与代理服务器建立一个<strong>基于 TCP</strong> 的 <code>HTTP CONNECT</code> 请求。它从不尝试使用其他协议。</p>
</li>
<li class="">
<p>在 <strong>TUN 模式</strong> 下，浏览器认为它正在直接与互联网对话。为了追求速度，对于任何支持最新协议的服务器（如谷歌、Cloudflare，以及此处的 Claude），它会优先尝试使用现代的 <strong>QUIC 协议（运行于 UDP 之上）</strong>。</p>
</li>
</ul>
<p>问题至此水落石出：用户的代理服务器不支持 UDP 转发。当 Clash 试图将来自 Claude 的 UDP 数据包发送到代理服务器时，操作失败了。这条规则被跳过，流量一路向下，最终落入了配置末尾的 <code>MATCH</code> 规则，而该规则很可能被设置为 <code>DIRECT</code>。</p>
<p>这完美地解释了为什么规则模式能成功（因为它强制使用 TCP），而 TUN 模式会失败（因为它允许使用 UDP）。</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第三部分优雅的脚本解决方案">第三部分：优雅的脚本解决方案<a href="https://your-docusaurus-site.example.com/troubleshooting-clash-tun-mode#%E7%AC%AC%E4%B8%89%E9%83%A8%E5%88%86%E4%BC%98%E9%9B%85%E7%9A%84%E8%84%9A%E6%9C%AC%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88" class="hash-link" aria-label="第三部分：优雅的脚本解决方案的直接链接" title="第三部分：优雅的脚本解决方案的直接链接" translate="no">​</a></h2>
<p>最后一步是在代理节点上启用 UDP 转发。用户的 Trojan 节点配置如下：</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"xxxx.com:443"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"server"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"xxxx.com"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"port"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">443</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"trojan"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"password"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"xxxx"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"sni"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"xxxx.com"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>要启用 UDP，只需增加一行：<code>"udp": true</code>。</p>
<p>手动修改配置文件当然可以，但如果订阅更新了怎么办？或者如果有几十个节点呢？这正是 Clash Verge <strong>扩展脚本</strong> 发挥其真正威力的地方。</p>
<p>脚本不仅可以添加规则，还可以在<strong>运行时</strong>修改整个配置对象。用户意识到，他们可以通过在现有脚本中添加一个简单的循环，来一劳永逸地解决这个问题。</p>
<p><strong>最终的完美脚本：</strong></p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">config</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> profileName</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 为所有代理节点添加或设置 'udp: true'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">proxies</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">proxies</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">proxy</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">proxy</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">udp</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 保留原有的添加域名规则的逻辑</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"proxy-groups"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">?.</span><span class="token method function property-access" style="color:#d73a49">at</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">rules</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">unshift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">DOMAIN-SUFFIX,claude.ai,</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">rules</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">unshift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">DOMAIN-SUFFIX,claude.com,</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> config</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>通过这一修改，每当配置文件加载时，脚本都会自动确保每一个代理服务器都启用了 UDP 转发。这是一个健壮的、"一次设置，永久有效"的解决方案。</p>
<p>在应用了这个最终脚本并重启核心后，问题迎刃而解。发往 <code>claude.ai</code> 的 <code>Tun(udp)</code> 流量现在被正确地路由到了指定的代理。</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="关键启示">关键启示<a href="https://your-docusaurus-site.example.com/troubleshooting-clash-tun-mode#%E5%85%B3%E9%94%AE%E5%90%AF%E7%A4%BA" class="hash-link" aria-label="关键启示的直接链接" title="关键启示的直接链接" translate="no">​</a></h2>
<p>这次排错之旅为我们掌握 Clash TUN 模式提供了几条至关重要的经验：</p>
<ol>
<li class="">
<p><strong>DNS 是必要条件：</strong> 要让基于域名的规则在 TUN 模式下生效，正确配置的 <code>fake-ip</code> DNS 是强制性的。</p>
</li>
<li class="">
<p><strong>小心过滤器：</strong> 密切关注 <code>fake-ip-filter</code>。一个配置错误的黑名单可能会成为你域名规则的"无声杀手"。通常，切换到 <code>whitelist</code> 模式更安全。</p>
</li>
<li class="">
<p><strong>TUN 模式暴露协议差异：</strong> TUN 模式允许应用程序像在开放网络上一样运行，这可能意味着使用 UDP (QUIC)。请为此做好准备。</p>
</li>
<li class="">
<p><strong>为你的代理启用 UDP：</strong> 如果你使用 TUN 模式，请确保你的代理节点已设置 <code>udp: true</code>。否则，许多现代网络服务都会出现问题。</p>
</li>
<li class="">
<p><strong>善用扩展脚本：</strong> 不要只用脚本来添加规则。它们是动态修改整个配置的强大工具，能让你的配置免受订阅更新的影响，并省去手动编辑的麻烦。</p>
</li>
</ol>
<p>通过理解这些层次，你就能从被 TUN 模式困扰，转变为驾驭它的全部力量，获得真正无缝和全面的路由体验。</p>]]></content>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="Gemini" term="Gemini"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[在离线服务器上安装 Node 模块]]></title>
        <id>https://your-docusaurus-site.example.com/install_node_modules_on_an_offline_server</id>
        <link href="https://your-docusaurus-site.example.com/install_node_modules_on_an_offline_server"/>
        <updated>2025-09-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[最近有需求，需要在一台离线服务器上安装 node_modules，尝试了以下办法：]]></summary>
        <content type="html"><![CDATA[<p>最近有需求，需要在一台离线服务器上安装 <code>node_modules</code>，尝试了以下办法：</p>
<ol>
<li class="">直接在外网 Windows 11 上将依赖安装好，将整个项目进行压缩，然后传输到离线服务器上，再进行解压。结果失败，因为某些包会执行 <code>postinstall</code> 脚本，编译一些系统相关的代码，导致失败。</li>
<li class="">先试用 <code>npm install</code> 安装依赖，然后使用 <code>package-lock.json</code> 文件将整个项目的依赖树全部下载成 <code>tgz</code> 文件，然后在内网执行 <code>npm install --no-registry --cache ./npm-cache --prefer-offline</code> 安装依赖。结果失败，原因未知。</li>
<li class="">在 <code>WSL</code> 中创建与离线服务器相同的系统环境，然后执行 <code>npm install</code> 安装依赖。打包再解压，依旧失败，与方法 1 相同，依旧提示缺少某些依赖。</li>
</ol>
<p>最后一个办法是使用 <code>verdaccio</code> 搭建一个私有仓库。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="安装-verdaccio">安装 verdaccio<a href="https://your-docusaurus-site.example.com/install_node_modules_on_an_offline_server#%E5%AE%89%E8%A3%85-verdaccio" class="hash-link" aria-label="安装 verdaccio的直接链接" title="安装 verdaccio的直接链接" translate="no">​</a></h2>
<p>这里使用 <code>docker</code> 安装 <code>verdaccio</code>，因为部署起来比较方便。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> run </span><span class="token parameter variable" style="color:#36acaa">-d</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--name</span><span class="token plain"> verdaccio </span><span class="token parameter variable" style="color:#36acaa">-p</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4873</span><span class="token plain">:4873 verdaccio/verdaccio</span><br></span></code></pre></div></div>
<p>或者进行目录挂载</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> run </span><span class="token parameter variable" style="color:#36acaa">-d</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--name</span><span class="token plain"> verdaccio </span><span class="token parameter variable" style="color:#36acaa">-p</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4873</span><span class="token plain">:4873 </span><span class="token parameter variable" style="color:#36acaa">-v</span><span class="token plain"> /path/to/verdaccio/conf:/verdaccio/conf </span><span class="token parameter variable" style="color:#36acaa">-v</span><span class="token plain"> /path/to/verdaccio/storage:/verdaccio/storage verdaccio/verdaccio</span><br></span></code></pre></div></div>
<p>这里有两种选择，一种是将仓库数据挂载到 <code>docker</code> 容器中，一种是直接将仓库数据挂载到本地。</p>
<p>第一种方法，需要每次都将容器导出为新的镜像，然后推送到离线服务器上。</p>
<p>第二种方法，直接将仓库数据挂载到本地，然后每次启动容器时，将本地仓库数据挂载到容器中，需要注意的是，必须先使用第一种方法，先从容器中导出默认的配置文件，放在 <code>/path/to/verdaccio/conf</code> 目录下，或则复制下方配置文件 <code>config.yaml</code> 到 <code>/path/to/verdaccio/conf</code> 目录下，否则容器会报错。</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">#</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># This is the default configuration file. It allows all users to do anything,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># please read carefully the documentation and best practices to</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># improve security.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Do not configure host and port under `listen` in this file</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># as it will be ignored when using docker.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># see https://verdaccio.org/docs/en/docker#docker-and-custom-port-configuration</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Look here for more config file examples:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://github.com/verdaccio/verdaccio/tree/6.x/conf</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Read about the best practices</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/best</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># path to a directory with all packages</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">storage</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> /verdaccio/storage/data</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># path to a directory with plugins to include</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">plugins</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> /verdaccio/plugins</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/webui</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">web</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">title</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Verdaccio</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># comment out to disable gravatar support</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># gravatar: false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># by default packages are ordercer ascendant (asc|desc)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># sort_packages: asc</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># convert your UI to the dark side</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># darkMode: true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># html_cache: true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># by default all features are displayed</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># login: true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># showInfo: true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># showSettings: true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># In combination with darkMode you can force specific theme</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># showThemeSwitch: true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># showFooter: true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># showSearch: true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># showRaw: true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># showDownloadTarball: true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">#  HTML tags injected after manifest &lt;scripts/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># scriptsBodyAfter:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">#    - '&lt;script type="text/javascript" src="https://my.company.com/customJS.min.js"&gt;&lt;/script&gt;'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">#  HTML tags injected before ends &lt;/head&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">#  metaScripts:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">#    - '&lt;script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.slim.min.js"&gt;&lt;/script&gt;'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">#    - '&lt;script type="text/javascript" src="https://browser.sentry-cdn.com/5.15.5/bundle.min.js"&gt;&lt;/script&gt;'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">#    - '&lt;meta name="robots" content="noindex" /&gt;'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">#  HTML tags injected first child at &lt;body/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">#  bodyBefore:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">#    - '&lt;div id="myId"&gt;html before webpack scripts&lt;/div&gt;'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">#  Public path for template manifest scripts (only manifest)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">#  publicPath: http://somedomain.org/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/configuration#authentication</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">auth</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">htpasswd</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">file</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> /verdaccio/storage/htpasswd</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># Maximum amount of users allowed to register, defaults to "+infinity".</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># You can set this to -1 to disable registration.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># max_users: 1000</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># Hash algorithm, possible options are: "bcrypt", "md5", "sha1", "crypt".</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># algorithm: bcrypt # by default is crypt, but is recommended use bcrypt for new installations</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># Rounds number for "bcrypt", will be ignored for other algorithms.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># rounds: 10</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/configuration#uplinks</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># a list of other known repositories we can talk to</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">uplinks</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">npmjs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//registry.npmmirror.com/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Learn how to protect your packages</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/protect-your-dependencies/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/configuration#packages</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">packages</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">"@*/*"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># scoped packages</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">access</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $all</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">publish</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $authenticated</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">unpublish</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $authenticated</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> npmjs</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">"**"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># allow all users (including non-authenticated users) to read and</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># publish all packages</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">#</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># you can specify usernames/groupnames (depending on your auth plugin)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># and three keywords: "$all", "$anonymous", "$authenticated"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">access</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $all</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># allow all known users to publish/publish packages</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># (anyone can register by default, remember?)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">publish</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $authenticated</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">unpublish</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> $authenticated</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># if package is not available locally, proxy requests to 'npmjs' registry</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">proxy</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> npmjs</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># To improve your security configuration and  avoid dependency confusion</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># consider removing the proxy property for private packages</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/best#remove-proxy-to-increase-security-at-private-packages</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/configuration#server</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># You can specify HTTP/1.1 server keep alive timeout in seconds for incoming connections.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># A value of 0 makes the http server behave similarly to Node.js versions prior to 8.0.0, which did not have a keep-alive timeout.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># WORKAROUND: Through given configuration you can workaround following issue https://github.com/verdaccio/verdaccio/issues/301. Set to 0 in case 60 is not enough.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">server</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">keepAliveTimeout</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">60</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Allow `req.ip` to resolve properly when Verdaccio is behind a proxy or load-balancer</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># See: https://expressjs.com/en/guide/behind-proxies.html</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># trustProxy: '127.0.0.1'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/configuration#offline-publish</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># publish:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#   allow_offline: false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/configuration#url-prefix</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># url_prefix: /verdaccio/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># VERDACCIO_PUBLIC_URL='https://somedomain.org';</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># url_prefix: '/my_prefix'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># // url -&gt; https://somedomain.org/my_prefix/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># VERDACCIO_PUBLIC_URL='https://somedomain.org';</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># url_prefix: '/'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># // url -&gt; https://somedomain.org/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># VERDACCIO_PUBLIC_URL='https://somedomain.org/first_prefix';</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># url_prefix: '/second_prefix'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># // url -&gt; https://somedomain.org/second_prefix/'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/configuration#security</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># security:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#   api:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#     legacy: true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#     # recomended set to true for older installations</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#     migrateToSecureLegacySignature: true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#     jwt:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#       sign:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#         expiresIn: 29d</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#       verify:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#         someProp: [value]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#    web:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#      sign:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#        expiresIn: 1h # 1 hour by default</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#      verify:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#         someProp: [value]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/configuration#user-rate-limit</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># userRateLimit:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#   windowMs: 50000</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#   max: 1000</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/configuration#max-body-size</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># max_body_size: 10mb</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/configuration#listen-port</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># listen:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># - localhost:4873            # default value</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># - http://localhost:4873     # same thing</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># - 0.0.0.0:4873              # listen on all addresses (INADDR_ANY)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># - https://example.org:4873  # if you want to use https</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># - "[::1]:4873"                # ipv6</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># - unix:/tmp/verdaccio.sock    # unix socket</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># The HTTPS configuration is useful if you do not consider use a HTTP Proxy</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/configuration#https</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#   key: ./path/verdaccio-key.pem</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#   cert: ./path/verdaccio-cert.pem</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#   ca: ./path/verdaccio-csr.pem</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/configuration#proxy</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># http_proxy: http://something.local/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https_proxy: https://something.local/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/configuration#notifications</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># notify:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#   method: POST</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#   headers: [{ "Content-Type": "application/json" }]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#   endpoint: https://usagge.hipchat.com/v2/room/3729485/notification?auth_token=mySecretToken</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#   content: '{"color":"green","message":"New package published: * {{ name }}*","notify":true,"message_format":"text"}'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">middlewares</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">audit</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">enabled</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># https://verdaccio.org/docs/logger</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># log settings</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">log</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> stdout</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">format</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> pretty</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">level</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#experiments:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#  # support for npm token command</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#  token: false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#  # enable tarball URL redirect for hosting tarball with a different server, the tarball_url_redirect can be a template string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#  tarball_url_redirect: 'https://mycdn.com/verdaccio/${packageName}/${filename}'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#  # the tarball_url_redirect can be a function, takes packageName and filename and returns the url, when working with a js configuration file</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#  tarball_url_redirect(packageName, filename) {</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#    const signedUrl = // generate a signed url</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#    return signedUrl;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#  }</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># translate your registry, api i18n not available yet</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># i18n:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># list of the available translations https://github.com/verdaccio/verdaccio/blob/master/packages/plugins/ui-theme/src/i18n/ABOUT_TRANSLATIONS.md</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#   web: en-US</span><br></span></code></pre></div></div>
<p>按需选择。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置-verdaccio">配置 verdaccio<a href="https://your-docusaurus-site.example.com/install_node_modules_on_an_offline_server#%E9%85%8D%E7%BD%AE-verdaccio" class="hash-link" aria-label="配置 verdaccio的直接链接" title="配置 verdaccio的直接链接" translate="no">​</a></h2>
<p>主要是将 <code>npmjs</code> 的地址改为国内的镜像地址，或者直接将 <code>npmjs</code> 的地址改为离线服务器地址。</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">uplinks</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">npmjs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//registry.npmmirror.com/</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="重新安装依赖">重新安装依赖<a href="https://your-docusaurus-site.example.com/install_node_modules_on_an_offline_server#%E9%87%8D%E6%96%B0%E5%AE%89%E8%A3%85%E4%BE%9D%E8%B5%96" class="hash-link" aria-label="重新安装依赖的直接链接" title="重新安装依赖的直接链接" translate="no">​</a></h2>
<ol>
<li class="">
<p>删除 <code>node_modules</code> 文件夹</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">npx rimraf node_modules</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>删除 <code>package-lock.json</code> 文件</p>
</li>
<li class="">
<p>删除 <code>npm</code> 缓存，这一步非常重要，否则某些依赖可能会无法被缓存到 verdaccio 中</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> cache clean </span><span class="token parameter variable" style="color:#36acaa">--force</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>安装依赖</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--registry</span><span class="token plain"> http://localhost:4873</span><br></span></code></pre></div></div>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="离线环境安装">离线环境安装<a href="https://your-docusaurus-site.example.com/install_node_modules_on_an_offline_server#%E7%A6%BB%E7%BA%BF%E7%8E%AF%E5%A2%83%E5%AE%89%E8%A3%85" class="hash-link" aria-label="离线环境安装的直接链接" title="离线环境安装的直接链接" translate="no">​</a></h2>
<ol>
<li class="">
<p>部署 docker 容器</p>
</li>
<li class="">
<p>安装依赖</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--registry</span><span class="token plain"> http://localhost:4873</span><br></span></code></pre></div></div>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="非-npm-包安装">非 npm 包安装<a href="https://your-docusaurus-site.example.com/install_node_modules_on_an_offline_server#%E9%9D%9E-npm-%E5%8C%85%E5%AE%89%E8%A3%85" class="hash-link" aria-label="非 npm 包安装的直接链接" title="非 npm 包安装的直接链接" translate="no">​</a></h2>
<p>有一些依赖并非通过 <code>npm</code> 发布，而是自己的渠道，这时可以执行以下方案：</p>
<ol>
<li class="">
<p>下载并解压 <code>tgz</code> 文件</p>
</li>
<li class="">
<p>执行 <code>npm addUser --registry http://localhost:4873</code> 登录</p>
</li>
<li class="">
<p>在项目根目录执行 <code>npm publish --registry http://localhost:4873</code> 发布</p>
</li>
<li class="">
<p>在内网环境中的 <code>package.json</code> 中添加以下配置：</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">"overrides"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"your-package"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"npm:your-package@version"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>安装依赖</p>
</li>
</ol>]]></content>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="node" term="node"/>
        <category label="npm" term="npm"/>
        <category label="verdaccio" term="verdaccio"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Docker 离线安装实战：从入门到精通的踩坑指南]]></title>
        <id>https://your-docusaurus-site.example.com/install-docker-on-an-offline-linux-server</id>
        <link href="https://your-docusaurus-site.example.com/install-docker-on-an-offline-linux-server"/>
        <updated>2025-09-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[以下内容均为 Gemini 2.5 Pro Deep Research 生成]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>以下内容均为 <code>Gemini 2.5 Pro Deep Research</code> 生成</p>
</blockquote>
<p>在物理隔离或网络受限的环境中部署 Docker，是许多系统管理员面临的共同挑战。这不仅仅是下载一个安装包那么简单，而是一个涉及依赖解析、环境差异和软件包冲突的系统工程。本文将通过一个完整的实战案例，带您走过在类 RHEL 系统（如 CentOS, RHEL, openEuler）上离线安装 Docker 的每一步，并详细记录我们遇到的每一个错误、分析其根本原因，最终给出精准的解决方案。这不仅是一份操作指南，更是一份宝贵的排错实录。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第一阶段在线准备收集所有必要弹药">第一阶段：在线准备——收集所有必要"弹药"<a href="https://your-docusaurus-site.example.com/install-docker-on-an-offline-linux-server#%E7%AC%AC%E4%B8%80%E9%98%B6%E6%AE%B5%E5%9C%A8%E7%BA%BF%E5%87%86%E5%A4%87%E6%94%B6%E9%9B%86%E6%89%80%E6%9C%89%E5%BF%85%E8%A6%81%E5%BC%B9%E8%8D%AF" class="hash-link" aria-label="第一阶段：在线准备——收集所有必要&quot;弹药&quot;的直接链接" title="第一阶段：在线准备——收集所有必要&quot;弹药&quot;的直接链接" translate="no">​</a></h2>
<p>我们的第一步是在一台可以访问互联网的"在线"计算机上，下载 Docker Engine 及其所有的依赖项。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第1步添加-docker-官方软件仓库">第1步：添加 Docker 官方软件仓库<a href="https://your-docusaurus-site.example.com/install-docker-on-an-offline-linux-server#%E7%AC%AC1%E6%AD%A5%E6%B7%BB%E5%8A%A0-docker-%E5%AE%98%E6%96%B9%E8%BD%AF%E4%BB%B6%E4%BB%93%E5%BA%93" class="hash-link" aria-label="第1步：添加 Docker 官方软件仓库的直接链接" title="第1步：添加 Docker 官方软件仓库的直接链接" translate="no">​</a></h3>
<p>在全新的系统中，软件包管理器（如 dnf）并不知道从哪里可以找到 Docker 的官方社区版（docker-ce）。如果我们直接尝试下载，就会遇到第一个错误：</p>
<p>❌ <strong>初始错误 #1: No package docker-ce available</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># dnf download --resolve docker-ce...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Error: No package docker-ce available.</span><br></span></code></pre></div></div>
<p>✅ <strong>解决方案</strong>：我们需要手动将 Docker 的官方仓库地址添加到系统的配置中。这样，dnf 才能索引到相关的软件包。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 在您的在线计算机上执行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">sudo</span><span class="token plain"> dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第2步安装-dnf-下载插件">第2步：安装 dnf 下载插件<a href="https://your-docusaurus-site.example.com/install-docker-on-an-offline-linux-server#%E7%AC%AC2%E6%AD%A5%E5%AE%89%E8%A3%85-dnf-%E4%B8%8B%E8%BD%BD%E6%8F%92%E4%BB%B6" class="hash-link" aria-label="第2步：安装 dnf 下载插件的直接链接" title="第2步：安装 dnf 下载插件的直接链接" translate="no">​</a></h3>
<p>在某些精简安装的系统中，dnf 的 download 功能可能不是内置的，而是通过插件提供。这时，您可能会遇到第二个报错：</p>
<p>❌ <strong>初始错误 #2: No such command: download</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># dnf download --resolve docker-ce...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">No such command: download. Please use /usr/bin/dnf </span><span class="token parameter variable" style="color:#36acaa">--help</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">It could be a DNF plugin command, try: </span><span class="token string" style="color:#e3116c">"dnf install 'dnf-command(download)'"</span><br></span></code></pre></div></div>
<p>✅ <strong>解决方案</strong>：报错信息已经给出了明确的指引。我们需要安装提供这个命令的插件包，它通常是 dnf-plugins-core 1。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 在您的在线计算机上执行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">sudo</span><span class="token plain"> dnf </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'dnf-command(download)'</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第3步下载-docker-及其完整依赖树">第3步：下载 Docker 及其完整依赖树<a href="https://your-docusaurus-site.example.com/install-docker-on-an-offline-linux-server#%E7%AC%AC3%E6%AD%A5%E4%B8%8B%E8%BD%BD-docker-%E5%8F%8A%E5%85%B6%E5%AE%8C%E6%95%B4%E4%BE%9D%E8%B5%96%E6%A0%91" class="hash-link" aria-label="第3步：下载 Docker 及其完整依赖树的直接链接" title="第3步：下载 Docker 及其完整依赖树的直接链接" translate="no">​</a></h3>
<p>准备工作就绪，现在我们可以正式下载所有需要的 .rpm 文件了。然而，即使仓库配置正确，我们仍然可能遇到由系统版本差异导致的下载失败。</p>
<p>❌ <strong>初始错误 #3: Status code: 404 for... repomd.xml</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Errors during downloading metadata for repository 'docker-ce-stable':</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> - Status code: 404 for https://download.docker.com/linux/centos/24.03LTS_SP1/x86_64/stable/repodata/repomd.xml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Error: Failed to download metadata for repo 'docker-ce-stable'</span><br></span></code></pre></div></div>
<p>这个错误告诉我们，dnf 尝试访问的 URL 是无效的。它自动将您系统的特定版本号（如 24.03LTS_SP1）拼接到了 URL 中，但 Docker 的仓库是按主版本号（如 8 或 9）组织的 3。</p>
<p>✅ <strong>解决方案</strong>：我们需要在命令中强制指定一个与 Docker 仓库结构兼容的发行版主版本号，使用 --releasever 标志即可 4。对于大多数现代系统，这个值是 9。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 在您的在线计算机上执行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 创建一个目录来存放所有软件包</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">mkdir</span><span class="token plain"> docker-rpm-packages</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin class-name">cd</span><span class="token plain"> docker-rpm-packages</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 执行最终的下载命令</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">sudo</span><span class="token plain"> dnf download </span><span class="token parameter variable" style="color:#36acaa">--releasever</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">9</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--resolve</span><span class="token plain"> docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin</span><br></span></code></pre></div></div>
<p>执行成功后，您的 docker-rpm-packages 目录里会装满所有离线安装所需的 .rpm 文件。至此，在线准备阶段圆满完成。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第二阶段离线安装直面冲突与挑战">第二阶段：离线安装——直面冲突与挑战<a href="https://your-docusaurus-site.example.com/install-docker-on-an-offline-linux-server#%E7%AC%AC%E4%BA%8C%E9%98%B6%E6%AE%B5%E7%A6%BB%E7%BA%BF%E5%AE%89%E8%A3%85%E7%9B%B4%E9%9D%A2%E5%86%B2%E7%AA%81%E4%B8%8E%E6%8C%91%E6%88%98" class="hash-link" aria-label="第二阶段：离线安装——直面冲突与挑战的直接链接" title="第二阶段：离线安装——直面冲突与挑战的直接链接" translate="no">​</a></h2>
<p>现在，我们将准备好的 docker-rpm-packages 目录通过 U 盘等物理介质，完整地复制到目标离线服务器上。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第4步执行安装">第4步：执行安装<a href="https://your-docusaurus-site.example.com/install-docker-on-an-offline-linux-server#%E7%AC%AC4%E6%AD%A5%E6%89%A7%E8%A1%8C%E5%AE%89%E8%A3%85" class="hash-link" aria-label="第4步：执行安装的直接链接" title="第4步：执行安装的直接链接" translate="no">​</a></h3>
<p>进入离线服务器上的软件包目录，我们开始执行安装。</p>
<p>❌ <strong>关键错误 #4: 文件冲突</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># sudo dnf install *.rpm --disablerepo=*</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">file</span><span class="token plain"> /usr/bin/docker-proxy from </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> of docker-ce</span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">. conflicts with </span><span class="token function" style="color:#d73a49">file</span><span class="token plain"> from package libnetwork</span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span></code></pre></div></div>
<p>这是一个非常典型的冲突。错误信息表明，我们尝试安装的官方 docker-ce 包，与离线系统上一个已存在的 libnetwork 包（通常是操作系统自带的容器网络组件）发生了文件冲突 5。</p>
<p>✅ <strong>第一次尝试：使用 --allowerasing</strong></p>
<p>dnf 提供了一个强大的参数 --allowerasing，用于授权它在解决冲突时自动移除旧的、有冲突的软件包 4。这是解决此类问题的首选标准方法。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 在您的离线服务器上执行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">sudo</span><span class="token plain"> dnf </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> *.rpm </span><span class="token parameter variable" style="color:#36acaa">--disablerepo</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">* </span><span class="token parameter variable" style="color:#36acaa">--allowerasing</span><br></span></code></pre></div></div>
<p>然而，在某些复杂的系统环境中（如此次实战中的 openEuler），即使添加了这个参数，dnf 在最后的"事务测试"阶段仍然可能因为无法安全地自动解决冲突而报错退出。</p>
<p>❌ <strong>关键错误 #5: 事务测试失败</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># sudo dnf install *.rpm --disablerepo=* --allowerasing</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Running transaction </span><span class="token builtin class-name">test</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Error: Transaction </span><span class="token builtin class-name">test</span><span class="token plain"> error:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">file</span><span class="token plain"> /usr/bin/docker-proxy from </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> of docker-ce</span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">. conflicts with </span><span class="token function" style="color:#d73a49">file</span><span class="token plain"> from package libnetwork</span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span></code></pre></div></div>
<p>✅ <strong>最终解决方案：手动移除冲突根源</strong></p>
<p>当自动化的解决方案失效时，我们需要进行更精确的手动干预。既然 dnf 无法安全地为我们移除 libnetwork，那我们就亲自动手。首先，手动卸载引发冲突的软件包。移除这个包是安全的，因为我们即将安装的 docker-ce 会提供功能完整且版本匹配的替代品 8。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 在您的离线服务器上执行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">sudo</span><span class="token plain"> dnf remove libnetwork</span><br></span></code></pre></div></div>
<p>dnf 可能会提示此操作会一并移除其他依赖包，确认即可。然后，再次执行安装命令。在清除了最主要的障碍后，我们再次运行带有 --allowerasing 的安装命令，以处理任何其他潜在的次要冲突。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 在您的离线服务器上执行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">sudo</span><span class="token plain"> dnf </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> *.rpm </span><span class="token parameter variable" style="color:#36acaa">--disablerepo</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">* </span><span class="token parameter variable" style="color:#36acaa">--allowerasing</span><br></span></code></pre></div></div>
<p>这一次，安装过程畅通无阻，成功完成。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第三阶段启动与验证">第三阶段：启动与验证<a href="https://your-docusaurus-site.example.com/install-docker-on-an-offline-linux-server#%E7%AC%AC%E4%B8%89%E9%98%B6%E6%AE%B5%E5%90%AF%E5%8A%A8%E4%B8%8E%E9%AA%8C%E8%AF%81" class="hash-link" aria-label="第三阶段：启动与验证的直接链接" title="第三阶段：启动与验证的直接链接" translate="no">​</a></h2>
<p>安装成功后，我们只需启动并验证 Docker 服务。</p>
<p><strong>启动并设置开机自启：</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">sudo</span><span class="token plain"> systemctl </span><span class="token builtin class-name">enable</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--now</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">docker</span><br></span></code></pre></div></div>
<p><strong>验证运行状态：</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">sudo</span><span class="token plain"> systemctl status </span><span class="token function" style="color:#d73a49">docker</span><br></span></code></pre></div></div>
<p><strong>运行 "Hello World"：</strong></p>
<p>由于是离线环境，您需要先将在在线计算机上用 docker save 打包好的镜像（例如 hello-world.tar）传输过来，然后用 docker load 导入。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 加载镜像</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">sudo</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> load </span><span class="token parameter variable" style="color:#36acaa">-i</span><span class="token plain"> /path/to/hello-world.tar</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 运行容器</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">sudo</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> run hello-world</span><br></span></code></pre></div></div>
<p>看到熟悉的欢迎信息，标志着本次高难度的离线 Docker 部署任务圆满成功。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://your-docusaurus-site.example.com/install-docker-on-an-offline-linux-server#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>离线安装 Docker 的过程充满了挑战，但每一个错误都为我们揭示了其底层的运作机制。通过这次实战，我们不仅学会了如何准备离线包，更掌握了一套从分析错误到解决问题的系统性方法，特别是如何处理顽固的软件包冲突。希望这份详尽的踩坑指南，能为您在未来的工作中扫清障碍。</p>]]></content>
        <author>
            <name>Gemini</name>
            <uri>https://gemini.google.com</uri>
        </author>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="docker" term="docker"/>
        <category label="openeuler" term="openeuler"/>
        <category label="linux" term="linux"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[HTML表单提交的两种方式：为什么有些按钮不触发 onSubmit]]></title>
        <id>https://your-docusaurus-site.example.com/form-submit-vs-requestsubmit</id>
        <link href="https://your-docusaurus-site.example.com/form-submit-vs-requestsubmit"/>
        <updated>2025-09-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[以下内容均为 Claude 4 sonnet 生成]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>以下内容均为 <code>Claude 4 sonnet</code> 生成</p>
</blockquote>
<p>在前端开发中，我们经常会遇到表单提交的问题。今天就来深入探讨一个看似简单却容易让人困惑的问题：为什么有些按钮能触发表单的 <code>onSubmit</code> 事件，而有些却不能？</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题场景">问题场景<a href="https://your-docusaurus-site.example.com/form-submit-vs-requestsubmit#%E9%97%AE%E9%A2%98%E5%9C%BA%E6%99%AF" class="hash-link" aria-label="问题场景的直接链接" title="问题场景的直接链接" translate="no">​</a></h2>
<p>让我们先看一个具体的例子：</p>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">FC</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token maybe-class-name">FormEvent</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> useRef </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token maybe-class-name">App</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">FC</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> form </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">useRef</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">HTMLFormElement</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onSubmit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">event</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">FormEvent</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token maybe-class-name">HTMLFormElement</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        event</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">preventDefault</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"表单已提交！"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">            </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">form</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">ref</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">form</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onSubmit</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">onSubmit</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">                </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">name</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">text</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">                </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">submit</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">内部提交按钮</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">            </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">form</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">            </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> form</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">current</span><span class="token tag script language-javascript operator" style="color:#393A34">?.</span><span class="token tag script language-javascript method function property-access" style="color:#d73a49">submit</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">外部提交按钮</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>运行这段代码你会发现：</p>
<ul>
<li class="">点击"内部提交按钮"：控制台输出"表单已提交！"</li>
<li class="">点击"外部提交按钮"：控制台没有任何输出</li>
</ul>
<p>这是为什么呢？</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="原理解析">原理解析<a href="https://your-docusaurus-site.example.com/form-submit-vs-requestsubmit#%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90" class="hash-link" aria-label="原理解析的直接链接" title="原理解析的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="方式一标准表单提交触发-onsubmit">方式一：标准表单提交（触发 onSubmit）<a href="https://your-docusaurus-site.example.com/form-submit-vs-requestsubmit#%E6%96%B9%E5%BC%8F%E4%B8%80%E6%A0%87%E5%87%86%E8%A1%A8%E5%8D%95%E6%8F%90%E4%BA%A4%E8%A7%A6%E5%8F%91-onsubmit" class="hash-link" aria-label="方式一：标准表单提交（触发 onSubmit）的直接链接" title="方式一：标准表单提交（触发 onSubmit）的直接链接" translate="no">​</a></h3>
<div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">submit</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">内部提交按钮</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<p>当我们点击这个按钮时，发生了以下过程：</p>
<ol>
<li class="">浏览器识别到这是一个 <code>type="submit"</code> 的按钮</li>
<li class="">浏览器查找该按钮所属的表单</li>
<li class="">浏览器触发表单的 <code>submit</code> 事件</li>
<li class="">我们的 <code>onSubmit</code> 事件处理函数被调用</li>
<li class="">如果没有 <code>preventDefault()</code>，表单会被实际提交</li>
</ol>
<p>这是<strong>标准的HTML表单提交流程</strong>，完全符合Web标准。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="方式二程序化提交不触发-onsubmit">方式二：程序化提交（不触发 onSubmit）<a href="https://your-docusaurus-site.example.com/form-submit-vs-requestsubmit#%E6%96%B9%E5%BC%8F%E4%BA%8C%E7%A8%8B%E5%BA%8F%E5%8C%96%E6%8F%90%E4%BA%A4%E4%B8%8D%E8%A7%A6%E5%8F%91-onsubmit" class="hash-link" aria-label="方式二：程序化提交（不触发 onSubmit）的直接链接" title="方式二：程序化提交（不触发 onSubmit）的直接链接" translate="no">​</a></h3>
<div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> form</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">current</span><span class="token tag script language-javascript operator" style="color:#393A34">?.</span><span class="token tag script language-javascript method function property-access" style="color:#d73a49">submit</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">外部提交按钮</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<p>当我们点击这个按钮时：</p>
<ol>
<li class="">执行 <code>onClick</code> 处理函数</li>
<li class="">调用 <code>form.submit()</code> 方法</li>
<li class="">表单被直接提交，<strong>但不触发 <code>submit</code> 事件</strong></li>
<li class=""><code>onSubmit</code> 处理函数不会被调用</li>
</ol>
<p><strong>关键点</strong>：根据HTML规范，程序化调用 <code>HTMLFormElement.submit()</code> 方法会绕过表单验证和事件触发机制。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="为什么会有这种设计">为什么会有这种设计？<a href="https://your-docusaurus-site.example.com/form-submit-vs-requestsubmit#%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BC%9A%E6%9C%89%E8%BF%99%E7%A7%8D%E8%AE%BE%E8%AE%A1" class="hash-link" aria-label="为什么会有这种设计？的直接链接" title="为什么会有这种设计？的直接链接" translate="no">​</a></h2>
<p>这种设计是有意为之的：</p>
<ol>
<li class=""><strong>性能考虑</strong>：程序化提交通常用于自动化场景，跳过事件处理可以提高性能</li>
<li class=""><strong>避免无限循环</strong>：如果在 <code>onSubmit</code> 中调用 <code>form.submit()</code>，可能导致无限递归</li>
<li class=""><strong>明确区分</strong>：用户操作和程序操作应该有不同的行为模式</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="实际应用中的解决方案">实际应用中的解决方案<a href="https://your-docusaurus-site.example.com/form-submit-vs-requestsubmit#%E5%AE%9E%E9%99%85%E5%BA%94%E7%94%A8%E4%B8%AD%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88" class="hash-link" aria-label="实际应用中的解决方案的直接链接" title="实际应用中的解决方案的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案一手动调用事件处理函数">方案一：手动调用事件处理函数<a href="https://your-docusaurus-site.example.com/form-submit-vs-requestsubmit#%E6%96%B9%E6%A1%88%E4%B8%80%E6%89%8B%E5%8A%A8%E8%B0%83%E7%94%A8%E4%BA%8B%E4%BB%B6%E5%A4%84%E7%90%86%E5%87%BD%E6%95%B0" class="hash-link" aria-label="方案一：手动调用事件处理函数的直接链接" title="方案一：手动调用事件处理函数的直接链接" translate="no">​</a></h3>
<div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">button onClick</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">form</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">current</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 手动调用 onSubmit 处理函数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> syntheticEvent </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token spread operator" style="color:#393A34">...</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token literal-property property" style="color:#36acaa">currentTarget</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> form</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">current</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token literal-property property" style="color:#36acaa">target</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> form</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">current</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function-variable function" style="color:#d73a49">preventDefault</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">onSubmit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">syntheticEvent </span><span class="token keyword module" style="color:#00009f">as</span><span class="token plain"> </span><span class="token maybe-class-name">FormEvent</span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">HTMLFormElement</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">}}&gt;外部提交按钮</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案二使用-requestsubmit推荐">方案二：使用 requestSubmit()（推荐）<a href="https://your-docusaurus-site.example.com/form-submit-vs-requestsubmit#%E6%96%B9%E6%A1%88%E4%BA%8C%E4%BD%BF%E7%94%A8-requestsubmit%E6%8E%A8%E8%8D%90" class="hash-link" aria-label="方案二：使用 requestSubmit()（推荐）的直接链接" title="方案二：使用 requestSubmit()（推荐）的直接链接" translate="no">​</a></h3>
<div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> form</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">current</span><span class="token tag script language-javascript operator" style="color:#393A34">?.</span><span class="token tag script language-javascript method function property-access" style="color:#d73a49">requestSubmit</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">外部提交按钮</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<p><code>requestSubmit()</code> 是HTML5的新方法，它：</p>
<ul>
<li class=""><strong>会触发</strong> <code>submit</code> 事件</li>
<li class="">会执行表单验证</li>
<li class="">行为类似于点击提交按钮</li>
</ul>
<p><strong>注意</strong>：<code>requestSubmit()</code> 的浏览器兼容性比 <code>submit()</code> 稍差，在一些旧版本浏览器中不支持。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案三模拟点击提交按钮">方案三：模拟点击提交按钮<a href="https://your-docusaurus-site.example.com/form-submit-vs-requestsubmit#%E6%96%B9%E6%A1%88%E4%B8%89%E6%A8%A1%E6%8B%9F%E7%82%B9%E5%87%BB%E6%8F%90%E4%BA%A4%E6%8C%89%E9%92%AE" class="hash-link" aria-label="方案三：模拟点击提交按钮的直接链接" title="方案三：模拟点击提交按钮的直接链接" translate="no">​</a></h3>
<div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> submitButtonRef </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> useRef</span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">HTMLButtonElement</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">(null)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">// 在JSX中</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">form</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">ref</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">form</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onSubmit</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">onSubmit</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">name</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">text</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">ref</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">submitButtonRef</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">submit</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">内部提交按钮</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">form</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript" style="color:#00009f"> </span><span class="token tag script language-javascript arrow operator" style="color:#393A34">=&gt;</span><span class="token tag script language-javascript" style="color:#00009f"> submitButtonRef</span><span class="token tag script language-javascript punctuation" style="color:#393A34">.</span><span class="token tag script language-javascript property-access" style="color:#00009f">current</span><span class="token tag script language-javascript operator" style="color:#393A34">?.</span><span class="token tag script language-javascript method function property-access" style="color:#d73a49">click</span><span class="token tag script language-javascript punctuation" style="color:#393A34">(</span><span class="token tag script language-javascript punctuation" style="color:#393A34">)</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">外部提交按钮</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<p>这种方式通过模拟点击来触发标准的表单提交流程。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="最佳实践建议">最佳实践建议<a href="https://your-docusaurus-site.example.com/form-submit-vs-requestsubmit#%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%E5%BB%BA%E8%AE%AE" class="hash-link" aria-label="最佳实践建议的直接链接" title="最佳实践建议的直接链接" translate="no">​</a></h2>
<ol>
<li class=""><strong>优先使用标准提交按钮</strong>：在表单内使用 <code>type="submit"</code> 的按钮</li>
<li class=""><strong>需要程序化提交时优先考虑 <code>requestSubmit()</code></strong>：它更符合标准行为</li>
<li class=""><strong>做好兼容性处理</strong>：如果需要支持旧版本浏览器，提供降级方案</li>
<li class=""><strong>保持一致的用户体验</strong>：确保所有提交方式都有相同的验证和处理逻辑</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://your-docusaurus-site.example.com/form-submit-vs-requestsubmit#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>表单提交看似简单，实则涉及Web标准、浏览器实现和用户体验的多个层面。理解 <code>submit()</code> 和 <code>requestSubmit()</code> 的区别，以及它们与事件处理机制的关系，能帮助我们写出更健壮的表单处理代码。</p>
<p>记住这个核心原则：<strong>用户触发的提交会触发事件，程序触发的提交通常不会</strong>。掌握了这一点，你就能更好地控制表单的提交行为了。</p>]]></content>
        <author>
            <name>Claude</name>
            <uri>https://claude.ai</uri>
        </author>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="html" term="html"/>
        <category label="react" term="react"/>
        <category label="form" term="form"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[记录一次由 React Compiler 引起的 "bug"]]></title>
        <id>https://your-docusaurus-site.example.com/a-bug-with-react-compiler</id>
        <link href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler"/>
        <updated>2025-09-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[以下内容均为 Claude 4 sonnet 生成]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>以下内容均为 <code>Claude 4 sonnet</code> 生成</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题背景">问题背景<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#%E9%97%AE%E9%A2%98%E8%83%8C%E6%99%AF" class="hash-link" aria-label="问题背景的直接链接" title="问题背景的直接链接" translate="no">​</a></h2>
<p>最近在项目中启用了 React Compiler 后，遇到了一个令人困惑的问题。一段看似正常的代码在没有启用 React Compiler 时运行良好，但启用后却会在渲染阶段直接崩溃。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题代码">问题代码<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#%E9%97%AE%E9%A2%98%E4%BB%A3%E7%A0%81" class="hash-link" aria-label="问题代码的直接链接" title="问题代码的直接链接" translate="no">​</a></h2>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">FC</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> useState </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">Info</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    age</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token maybe-class-name">App</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">FC</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">info</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setInfo</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">useState</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">Info </span><span class="token generic-function generic class-name operator" style="color:#393A34">|</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name keyword" style="color:#00009f">undefined</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">undefined</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onClick</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">info</span><span class="token operator" style="color:#393A34">!</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 使用了非空断言</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">onClick</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token maybe-class-name">App</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题现象">问题现象<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#%E9%97%AE%E9%A2%98%E7%8E%B0%E8%B1%A1" class="hash-link" aria-label="问题现象的直接链接" title="问题现象的直接链接" translate="no">​</a></h2>
<p>启用 React Compiler 后，即使 <code>onClick</code> 事件从未被触发，应用也会在渲染过程中直接崩溃，报错：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Cannot read property 'name' of undefined</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题分析">问题分析<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90" class="hash-link" aria-label="问题分析的直接链接" title="问题分析的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="react-compiler-的工作原理">React Compiler 的工作原理<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#react-compiler-%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86" class="hash-link" aria-label="React Compiler 的工作原理的直接链接" title="React Compiler 的工作原理的直接链接" translate="no">​</a></h3>
<p>React Compiler 是一个编译时优化工具，它会：</p>
<ol>
<li class=""><strong>依赖分析</strong>：分析函数组件中的依赖关系</li>
<li class=""><strong>自动记忆化</strong>：为函数和值自动添加 <code>useMemo</code> 和 <code>useCallback</code></li>
<li class=""><strong>代码优化</strong>：重新组织代码以提高性能</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题根源">问题根源<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#%E9%97%AE%E9%A2%98%E6%A0%B9%E6%BA%90" class="hash-link" aria-label="问题根源的直接链接" title="问题根源的直接链接" translate="no">​</a></h3>
<p>React Compiler 在分析 <code>onClick</code> 函数时，发现它引用了 <code>info.name</code>，因此将 <code>info</code> 作为依赖项。为了优化性能，编译器可能会：</p>
<ol>
<li class="">将 <code>onClick</code> 函数包装在 <code>useCallback</code> 中</li>
<li class="">将 <code>info.name</code> 的访问提前到渲染阶段进行依赖收集</li>
<li class="">这导致在 <code>info</code> 还是 <code>undefined</code> 的初始渲染时就尝试访问 <code>info.name</code></li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="编译后的大致效果">编译后的大致效果<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#%E7%BC%96%E8%AF%91%E5%90%8E%E7%9A%84%E5%A4%A7%E8%87%B4%E6%95%88%E6%9E%9C" class="hash-link" aria-label="编译后的大致效果的直接链接" title="编译后的大致效果的直接链接" translate="no">​</a></h3>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 编译器可能生成类似这样的代码</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token maybe-class-name">App</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">FC</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">info</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setInfo</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">useState</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">Info </span><span class="token generic-function generic class-name operator" style="color:#393A34">|</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name keyword" style="color:#00009f">undefined</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">undefined</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 编译器为了依赖收集，可能在渲染时就访问了 info.name</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> onClick </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useCallback</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">info</span><span class="token operator" style="color:#393A34">!</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">info</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 注意这里的依赖</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:#393A34">=</span><span class="token tag script language-javascript punctuation" style="color:#393A34">{</span><span class="token tag script language-javascript" style="color:#00009f">onClick</span><span class="token tag script language-javascript punctuation" style="color:#393A34">}</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="解决方案">解决方案<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88" class="hash-link" aria-label="解决方案的直接链接" title="解决方案的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案一使用可选链操作符">方案一：使用可选链操作符<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#%E6%96%B9%E6%A1%88%E4%B8%80%E4%BD%BF%E7%94%A8%E5%8F%AF%E9%80%89%E9%93%BE%E6%93%8D%E4%BD%9C%E7%AC%A6" class="hash-link" aria-label="方案一：使用可选链操作符的直接链接" title="方案一：使用可选链操作符的直接链接" translate="no">​</a></h3>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onClick</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">info</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 使用可选链</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案二添加条件判断">方案二：添加条件判断<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#%E6%96%B9%E6%A1%88%E4%BA%8C%E6%B7%BB%E5%8A%A0%E6%9D%A1%E4%BB%B6%E5%88%A4%E6%96%AD" class="hash-link" aria-label="方案二：添加条件判断的直接链接" title="方案二：添加条件判断的直接链接" translate="no">​</a></h3>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onClick</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">info</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">info</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案三使用默认值">方案三：使用默认值<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#%E6%96%B9%E6%A1%88%E4%B8%89%E4%BD%BF%E7%94%A8%E9%BB%98%E8%AE%A4%E5%80%BC" class="hash-link" aria-label="方案三：使用默认值的直接链接" title="方案三：使用默认值的直接链接" translate="no">​</a></h3>
<div class="language-tsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-tsx codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">info</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> setInfo</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">useState</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">Info</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> age</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="经验总结">经验总结<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#%E7%BB%8F%E9%AA%8C%E6%80%BB%E7%BB%93" class="hash-link" aria-label="经验总结的直接链接" title="经验总结的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-避免在可能为空的对象上使用非空断言">1. 避免在可能为空的对象上使用非空断言<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#1-%E9%81%BF%E5%85%8D%E5%9C%A8%E5%8F%AF%E8%83%BD%E4%B8%BA%E7%A9%BA%E7%9A%84%E5%AF%B9%E8%B1%A1%E4%B8%8A%E4%BD%BF%E7%94%A8%E9%9D%9E%E7%A9%BA%E6%96%AD%E8%A8%80" class="hash-link" aria-label="1. 避免在可能为空的对象上使用非空断言的直接链接" title="1. 避免在可能为空的对象上使用非空断言的直接链接" translate="no">​</a></h3>
<p>非空断言 (<code>!</code>) 只是告诉 TypeScript 编译器忽略空值检查，但运行时仍可能出错。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-react-compiler-改变了代码执行时机">2. React Compiler 改变了代码执行时机<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#2-react-compiler-%E6%94%B9%E5%8F%98%E4%BA%86%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%97%B6%E6%9C%BA" class="hash-link" aria-label="2. React Compiler 改变了代码执行时机的直接链接" title="2. React Compiler 改变了代码执行时机的直接链接" translate="no">​</a></h3>
<p>启用 React Compiler 后，一些原本在事件处理中才会执行的代码可能会在渲染时执行。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-防御性编程的重要性">3. 防御性编程的重要性<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#3-%E9%98%B2%E5%BE%A1%E6%80%A7%E7%BC%96%E7%A8%8B%E7%9A%84%E9%87%8D%E8%A6%81%E6%80%A7" class="hash-link" aria-label="3. 防御性编程的重要性的直接链接" title="3. 防御性编程的重要性的直接链接" translate="no">​</a></h3>
<p>始终考虑变量可能为空的情况，使用可选链和条件判断。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-理解工具的工作原理">4. 理解工具的工作原理<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#4-%E7%90%86%E8%A7%A3%E5%B7%A5%E5%85%B7%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86" class="hash-link" aria-label="4. 理解工具的工作原理的直接链接" title="4. 理解工具的工作原理的直接链接" translate="no">​</a></h3>
<p>了解 React Compiler 等工具的工作机制，有助于预防和解决类似问题。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="最佳实践建议">最佳实践建议<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%E5%BB%BA%E8%AE%AE" class="hash-link" aria-label="最佳实践建议的直接链接" title="最佳实践建议的直接链接" translate="no">​</a></h2>
<ol>
<li class="">
<p><strong>启用严格的 TypeScript 配置</strong>：使用 <code>strict: true</code> 和 <code>strictNullChecks: true</code></p>
</li>
<li class="">
<p><strong>优先使用可选链</strong>：在访问可能为空的对象属性时使用 <code>?.</code></p>
</li>
<li class="">
<p><strong>避免过度使用非空断言</strong>：只在确实知道值不为空时使用 <code>!</code></p>
</li>
<li class="">
<p><strong>渐进式启用新工具</strong>：在小范围内测试新的编译工具，逐步推广</p>
</li>
<li class="">
<p><strong>完善的错误边界</strong>：设置 Error Boundary 来捕获和处理渲染时错误</p>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="结语">结语<a href="https://your-docusaurus-site.example.com/a-bug-with-react-compiler#%E7%BB%93%E8%AF%AD" class="hash-link" aria-label="结语的直接链接" title="结语的直接链接" translate="no">​</a></h2>
<p>这个案例提醒我们，新的编译优化工具虽然能带来性能提升，但也可能改变代码的执行行为。作为开发者，我们需要：</p>
<ul>
<li class="">理解工具的工作原理</li>
<li class="">编写更加健壮的代码</li>
<li class="">进行充分的测试</li>
<li class="">保持对新技术的学习和适应</li>
</ul>
<p>希望这个案例能帮助其他开发者避免类似的问题。</p>]]></content>
        <author>
            <name>Claude</name>
            <uri>https://claude.ai</uri>
        </author>
        <category label="react" term="react"/>
        <category label="react-compiler" term="react-compiler"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[TypeScript 类型推断的神秘陷阱：为什么缺少一个"无关"属性会影响泛型推断？]]></title>
        <id>https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap</id>
        <link href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap"/>
        <updated>2025-08-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[以下内容均为 Claude 4 sonnet 生成]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>以下内容均为 <code>Claude 4 sonnet</code> 生成</p>
</blockquote>
<p>在使用 TypeScript 开发过程中，你是否遇到过这样的困惑：明明某个属性看起来与泛型推断无关，但缺少它就会导致类型推断失败？今天我们来深入探讨这个有趣的现象。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题重现">问题重现<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#%E9%97%AE%E9%A2%98%E9%87%8D%E7%8E%B0" class="hash-link" aria-label="问题重现的直接链接" title="问题重现的直接链接" translate="no">​</a></h2>
<p>让我们先看一个具体的例子：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Item</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name builtin">number</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> render</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">render</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">getValue</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name constant" style="color:#36acaa">T</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Item</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> item</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">render </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> item</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">render</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">value </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 这样调用会导致类型推断失败</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getValue</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function-variable function" style="color:#d73a49">render</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> v </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 缺少 key 属性</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 但添加 key 属性后，T 就能正确推断为 number</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getValue</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"something"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function-variable function" style="color:#d73a49">render</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> v </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>你可能会疑惑：<code>key</code> 属性明明是固定的 <code>string</code> 类型，为什么它的存在与否会影响泛型 <code>T</code> 的推断？</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="深入分析typescript-类型推断的工作机制">深入分析：TypeScript 类型推断的工作机制<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#%E6%B7%B1%E5%85%A5%E5%88%86%E6%9E%90typescript-%E7%B1%BB%E5%9E%8B%E6%8E%A8%E6%96%AD%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%9C%BA%E5%88%B6" class="hash-link" aria-label="深入分析：TypeScript 类型推断的工作机制的直接链接" title="深入分析：TypeScript 类型推断的工作机制的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-结构完整性检查">1. 结构完整性检查<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#1-%E7%BB%93%E6%9E%84%E5%AE%8C%E6%95%B4%E6%80%A7%E6%A3%80%E6%9F%A5" class="hash-link" aria-label="1. 结构完整性检查的直接链接" title="1. 结构完整性检查的直接链接" translate="no">​</a></h3>
<p>TypeScript 的类型推断遵循<strong>结构完整性原则</strong>。当你传递一个对象字面量给泛型函数时，TypeScript 需要确保这个对象完全符合期望的类型结构。</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// TypeScript 的推断过程</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">getValue</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">render</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> v </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> v </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ↓</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 检查对象是否匹配 Item&lt;T&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ↓</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 发现缺少必需的 key 属性</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ↓</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 无法确定对象类型，放弃泛型推断</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// ↓</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// T 被推断为 unknown 或其他默认类型</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-类型推断的两阶段过程">2. 类型推断的两阶段过程<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#2-%E7%B1%BB%E5%9E%8B%E6%8E%A8%E6%96%AD%E7%9A%84%E4%B8%A4%E9%98%B6%E6%AE%B5%E8%BF%87%E7%A8%8B" class="hash-link" aria-label="2. 类型推断的两阶段过程的直接链接" title="2. 类型推断的两阶段过程的直接链接" translate="no">​</a></h3>
<p>TypeScript 的类型推断实际上是一个两阶段过程：</p>
<ol>
<li class="">
<p><strong>阶段一：结构验证</strong></p>
<ul>
<li class="">检查传入的参数是否符合函数签名</li>
<li class="">验证所有必需属性是否存在</li>
<li class="">如果结构不完整，推断过程提前终止</li>
</ul>
</li>
<li class="">
<p><strong>阶段二：类型推断</strong></p>
<ul>
<li class="">基于已验证的结构进行类型推断</li>
<li class="">从具体的属性值推断泛型参数</li>
<li class="">应用条件类型逻辑</li>
</ul>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-条件类型的复杂性">3. 条件类型的复杂性<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#3-%E6%9D%A1%E4%BB%B6%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%A4%8D%E6%9D%82%E6%80%A7" class="hash-link" aria-label="3. 条件类型的复杂性的直接链接" title="3. 条件类型的复杂性的直接链接" translate="no">​</a></h3>
<p>我们的例子中使用了条件类型：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name builtin">number</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> render</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">render</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>这种复杂的类型定义让 TypeScript 更加谨慎。它需要先确定 <code>T</code> 的类型，才能知道 <code>render</code> 属性是可选还是必需的。但要推断 <code>T</code>，又需要完整的对象结构。这形成了一个依赖循环，TypeScript 通过要求完整结构来打破这个循环。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="实际应用场景">实际应用场景<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#%E5%AE%9E%E9%99%85%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF" class="hash-link" aria-label="实际应用场景的直接链接" title="实际应用场景的直接链接" translate="no">​</a></h2>
<p>这种情况在实际开发中很常见，特别是在以下场景：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置对象设计">配置对象设计<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#%E9%85%8D%E7%BD%AE%E5%AF%B9%E8%B1%A1%E8%AE%BE%E8%AE%A1" class="hash-link" aria-label="配置对象设计的直接链接" title="配置对象设计的直接链接" translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Config</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    data</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    validator</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name builtin">string</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">val</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">boolean</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">never</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">processConfig</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name constant" style="color:#36acaa">T</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">config</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Config</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 处理逻辑</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="表单字段定义">表单字段定义<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#%E8%A1%A8%E5%8D%95%E5%AD%97%E6%AE%B5%E5%AE%9A%E4%B9%89" class="hash-link" aria-label="表单字段定义的直接链接" title="表单字段定义的直接链接" translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">FieldDef</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name builtin">number</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> min</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> max</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> pattern</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> RegExp </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="api-响应处理">API 响应处理<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#api-%E5%93%8D%E5%BA%94%E5%A4%84%E7%90%86" class="hash-link" aria-label="API 响应处理的直接链接" title="API 响应处理的直接链接" translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">ApiResponse</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    status</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    data</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">object</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> meta</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ResponseMeta </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="解决方案详解">解决方案详解<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E8%AF%A6%E8%A7%A3" class="hash-link" aria-label="解决方案详解的直接链接" title="解决方案详解的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案一调整类型定义calude-推荐">方案一：调整类型定义（Calude 推荐）<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#%E6%96%B9%E6%A1%88%E4%B8%80%E8%B0%83%E6%95%B4%E7%B1%BB%E5%9E%8B%E5%AE%9A%E4%B9%89calude-%E6%8E%A8%E8%8D%90" class="hash-link" aria-label="方案一：调整类型定义（Calude 推荐）的直接链接" title="方案一：调整类型定义（Calude 推荐）的直接链接" translate="no">​</a></h3>
<p>将不影响泛型推断的属性设为可选：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Item</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    key</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 改为可选属性</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name builtin">number</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> render</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">render</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 现在可以正常推断了</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getValue</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function-variable function" style="color:#d73a49">render</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> v </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案二显式类型注解">方案二：显式类型注解<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#%E6%96%B9%E6%A1%88%E4%BA%8C%E6%98%BE%E5%BC%8F%E7%B1%BB%E5%9E%8B%E6%B3%A8%E8%A7%A3" class="hash-link" aria-label="方案二：显式类型注解的直接链接" title="方案二：显式类型注解的直接链接" translate="no">​</a></h3>
<p>当你明确知道类型时，可以显式指定：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">getValue</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name builtin">number</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function-variable function" style="color:#d73a49">render</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> v </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案三分离核心类型1adybug-推荐">方案三：分离核心类型（1adybug 推荐）<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#%E6%96%B9%E6%A1%88%E4%B8%89%E5%88%86%E7%A6%BB%E6%A0%B8%E5%BF%83%E7%B1%BB%E5%9E%8B1adybug-%E6%8E%A8%E8%8D%90" class="hash-link" aria-label="方案三：分离核心类型（1adybug 推荐）的直接链接" title="方案三：分离核心类型（1adybug 推荐）的直接链接" translate="no">​</a></h3>
<p>将核心业务逻辑类型与辅助属性分离：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">ItemCore</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name builtin">number</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> render</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">render</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Item</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> ItemCore</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 为核心类型提供单独的函数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">getValueCore</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name constant" style="color:#36acaa">T</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> ItemCore</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> item</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">render </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> item</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">render</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">value </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案四使用工厂函数">方案四：使用工厂函数<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#%E6%96%B9%E6%A1%88%E5%9B%9B%E4%BD%BF%E7%94%A8%E5%B7%A5%E5%8E%82%E5%87%BD%E6%95%B0" class="hash-link" aria-label="方案四：使用工厂函数的直接链接" title="方案四：使用工厂函数的直接链接" translate="no">​</a></h3>
<p>创建辅助函数来构造完整对象：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">createItem</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name constant" style="color:#36acaa">T</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> render</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name builtin">number</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">undefined</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> key</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Item</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> key </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"default"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        value</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        render</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> Item</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token constant" style="color:#36acaa">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getValue</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">createItem</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> v </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="最佳实践建议">最佳实践建议<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%E5%BB%BA%E8%AE%AE" class="hash-link" aria-label="最佳实践建议的直接链接" title="最佳实践建议的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-优先考虑-api-设计">1. 优先考虑 API 设计<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#1-%E4%BC%98%E5%85%88%E8%80%83%E8%99%91-api-%E8%AE%BE%E8%AE%A1" class="hash-link" aria-label="1. 优先考虑 API 设计的直接链接" title="1. 优先考虑 API 设计的直接链接" translate="no">​</a></h3>
<p>在设计类型时，考虑哪些属性是核心的，哪些是辅助的：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 好的设计：核心属性在前，辅助属性可选</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">GoodItem</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    render</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name builtin">number</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">number</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    id</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    metadata</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 避免的设计：辅助属性必需</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">BadItem</span><span class="token class-name operator" style="color:#393A34">&lt;</span><span class="token class-name constant" style="color:#36acaa">T</span><span class="token class-name operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 辅助属性但是必需</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    metadata</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Record</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 可能不相关但必需</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    render</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-合理使用类型推断">2. 合理使用类型推断<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#2-%E5%90%88%E7%90%86%E4%BD%BF%E7%94%A8%E7%B1%BB%E5%9E%8B%E6%8E%A8%E6%96%AD" class="hash-link" aria-label="2. 合理使用类型推断的直接链接" title="2. 合理使用类型推断的直接链接" translate="no">​</a></h3>
<p>不要过度依赖类型推断，在复杂场景下适当使用显式类型：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 简单场景：依赖推断</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> simple </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getValue</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"something"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 复杂场景：显式指定</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> complex </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">getValue</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">ComplexType</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"something"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> complexData</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    render</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> customRenderer</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-提供类型友好的工厂函数">3. 提供类型友好的工厂函数<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#3-%E6%8F%90%E4%BE%9B%E7%B1%BB%E5%9E%8B%E5%8F%8B%E5%A5%BD%E7%9A%84%E5%B7%A5%E5%8E%82%E5%87%BD%E6%95%B0" class="hash-link" aria-label="3. 提供类型友好的工厂函数的直接链接" title="3. 提供类型友好的工厂函数的直接链接" translate="no">​</a></h3>
<p>为复杂类型提供便捷的构造函数：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> ItemBuilder </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function-variable function" style="color:#d73a49">forNumber</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> key</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> render</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">v</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> key </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">num_</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">value</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        value</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        render</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function-variable function" style="color:#d73a49">forString</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> key</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function-variable function" style="color:#d73a49">render</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">v</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token builtin">number</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> key </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">str_</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">value</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        value</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        render</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://your-docusaurus-site.example.com/typescript-generic-inference-missing-properties-trap#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>TypeScript 的类型推断看似神秘，实际上遵循着严格的逻辑：</p>
<ol>
<li class=""><strong>结构完整性优先</strong>：TypeScript 需要完整的对象结构才能进行类型推断</li>
<li class=""><strong>安全性考虑</strong>：宁可推断失败也不愿意产生不安全的类型</li>
<li class=""><strong>复杂性处理</strong>：条件类型等复杂特性会让推断更加保守</li>
</ol>
<p>理解这些原理有助于我们：</p>
<ul>
<li class="">设计更好的类型定义</li>
<li class="">写出更类型友好的代码</li>
<li class="">在推断失败时快速定位问题</li>
<li class="">选择合适的解决方案</li>
</ul>
<p>下次遇到类似问题时，你就知道这不是 TypeScript 的 bug，而是它保守而明智的设计选择。通过合理的类型设计和适当的显式注解，我们可以既享受类型推断的便利，又保证代码的类型安全。</p>
<hr>]]></content>
        <author>
            <name>Claude</name>
            <uri>https://claude.ai</uri>
        </author>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="typescript" term="typescript"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[@internationalized/date 中的 ZonedDateTime、CalendarDate、CalendarDateTime、Time 几种时间类型的区别]]></title>
        <id>https://your-docusaurus-site.example.com/differece-among-ZonedDateTime-CalendarDate-CalendarDateTime-Time</id>
        <link href="https://your-docusaurus-site.example.com/differece-among-ZonedDateTime-CalendarDate-CalendarDateTime-Time"/>
        <updated>2025-07-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[以下内容均为 Gemini 2.5 Pro 生成]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>以下内容均为 <code>Gemini 2.5 Pro</code> 生成</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="internationalizeddate深入解析四种核心时间类型">@internationalized/date：深入解析四种核心时间类型<a href="https://your-docusaurus-site.example.com/differece-among-ZonedDateTime-CalendarDate-CalendarDateTime-Time#internationalizeddate%E6%B7%B1%E5%85%A5%E8%A7%A3%E6%9E%90%E5%9B%9B%E7%A7%8D%E6%A0%B8%E5%BF%83%E6%97%B6%E9%97%B4%E7%B1%BB%E5%9E%8B" class="hash-link" aria-label="@internationalized/date：深入解析四种核心时间类型的直接链接" title="@internationalized/date：深入解析四种核心时间类型的直接链接" translate="no">​</a></h2>
<p>在 JavaScript 中处理日期和时间常常因为时区、日历系统和国际化等问题而变得复杂。<code>@internationalized/date</code> 库提供了一套强大且设计精良的工具来应对这些挑战。该库的核心是其不可变的时间对象：<code>ZonedDateTime</code>、<code>CalendarDate</code>、<code>CalendarDateTime</code> 和 <code>Time</code>。理解它们之间的差异对于正确和高效地处理日期与时间至关重要。</p>
<p>以下是这四种时间类型的详细区别：</p>
<hr>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="calendardate纯粹的日期"><code>CalendarDate</code>：纯粹的日期<a href="https://your-docusaurus-site.example.com/differece-among-ZonedDateTime-CalendarDate-CalendarDateTime-Time#calendardate%E7%BA%AF%E7%B2%B9%E7%9A%84%E6%97%A5%E6%9C%9F" class="hash-link" aria-label="calendardate纯粹的日期的直接链接" title="calendardate纯粹的日期的直接链接" translate="no">​</a></h3>
<p><code>CalendarDate</code> 对象表示一个不含任何时间信息的特定日期。它非常适合用来表示与一天中的具体时间无关的事件，例如：</p>
<ul>
<li class="">生日</li>
<li class="">节假日</li>
<li class="">全天日历事件</li>
</ul>
<p><strong>核心特性：</strong></p>
<ul>
<li class=""><strong>仅包含日期部分：</strong> 年、月、日。</li>
<li class=""><strong>无时间概念：</strong> 不涉及小时、分钟或秒。</li>
<li class=""><strong>无时区信息：</strong> 它代表的是一个日历上的日期，与任何特定时区无关。</li>
<li class=""><strong>支持多种日历系统：</strong> 可以表示公历（Gregorian）以及希伯来（Hebrew）、伊斯兰（Islamic）等多种日历。</li>
</ul>
<p><strong>示例：</strong></p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">CalendarDate</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@internationalized/date"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 表示 2025 年 7 月 24 日</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> birthday </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">CalendarDate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2025</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">7</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">24</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">birthday</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 输出: 2025-07-24</span><br></span></code></pre></div></div>
<hr>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="time纯粹的时间"><code>Time</code>：纯粹的时间<a href="https://your-docusaurus-site.example.com/differece-among-ZonedDateTime-CalendarDate-CalendarDateTime-Time#time%E7%BA%AF%E7%B2%B9%E7%9A%84%E6%97%B6%E9%97%B4" class="hash-link" aria-label="time纯粹的时间的直接链接" title="time纯粹的时间的直接链接" translate="no">​</a></h3>
<p>与 <code>CalendarDate</code> 相对，<code>Time</code> 对象表示一个不含任何日期信息的特定时间。它适用于表示与具体哪一天无关的时间点，例如：</p>
<ul>
<li class="">每天的闹钟时间</li>
<li class="">商店的营业时间</li>
</ul>
<p><strong>核心特性：</strong></p>
<ul>
<li class=""><strong>仅包含时间部分：</strong> 小时、分钟、秒和毫秒。</li>
<li class=""><strong>无日期概念：</strong> 不涉及年、月、日。</li>
<li class=""><strong>无时区信息：</strong> 它代表的是时钟上的一个时间，与任何特定时区无关。</li>
</ul>
<p><strong>示例：</strong></p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">Time</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@internationalized/date"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 表示上午 9 点 30 分</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> openingHour </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Time</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">9</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">30</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">openingHour</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 输出: 09:30:00</span><br></span></code></pre></div></div>
<hr>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="calendardatetime日期与时间的结合"><code>CalendarDateTime</code>：日期与时间的结合<a href="https://your-docusaurus-site.example.com/differece-among-ZonedDateTime-CalendarDate-CalendarDateTime-Time#calendardatetime%E6%97%A5%E6%9C%9F%E4%B8%8E%E6%97%B6%E9%97%B4%E7%9A%84%E7%BB%93%E5%90%88" class="hash-link" aria-label="calendardatetime日期与时间的结合的直接链接" title="calendardatetime日期与时间的结合的直接链接" translate="no">​</a></h3>
<p><code>CalendarDateTime</code> 对象是 <code>CalendarDate</code> 和 <code>Time</code> 的结合体，它表示一个具体的日期和时间，但 <strong>不包含任何时区信息</strong>。这在表示一个特定时间点，但该时间点在不同时区下可能对应不同实际时刻的场景中非常有用。</p>
<p><strong>核心特性：</strong></p>
<ul>
<li class=""><strong>包含日期和时间部分：</strong> 年、月、日、小时、分钟、秒。</li>
<li class=""><strong>无时区信息：</strong> 它是一个“本地”的日期时间，其确切的时间点取决于观察者所在的时区。</li>
<li class=""><strong>支持多种日历系统。</strong></li>
</ul>
<p><strong>示例：</strong></p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">CalendarDateTime</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@internationalized/date"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 表示 2025 年 10 月 26 日上午 10 点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> localEvent </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">CalendarDateTime</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2025</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">26</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">localEvent</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 输出: 2025-10-26T10:00:00</span><br></span></code></pre></div></div>
<p>这个时间可以被理解为“任何时区的上午10点”。</p>
<hr>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="zoneddatetime完整的带时区的日期时间"><code>ZonedDateTime</code>：完整的、带时区的日期时间<a href="https://your-docusaurus-site.example.com/differece-among-ZonedDateTime-CalendarDate-CalendarDateTime-Time#zoneddatetime%E5%AE%8C%E6%95%B4%E7%9A%84%E5%B8%A6%E6%97%B6%E5%8C%BA%E7%9A%84%E6%97%A5%E6%9C%9F%E6%97%B6%E9%97%B4" class="hash-link" aria-label="zoneddatetime完整的带时区的日期时间的直接链接" title="zoneddatetime完整的带时区的日期时间的直接链接" translate="no">​</a></h3>
<p><code>ZonedDateTime</code> 是这四种类型中信息最全面的对象。它表示一个在 <strong>特定时区</strong> 下的精确日期和时间。这是处理需要明确、无歧义时间点的最佳选择，例如：</p>
<ul>
<li class="">航班起飞时间</li>
<li class="">国际会议的安排</li>
<li class="">任何需要考虑夏令时和时区转换的场景</li>
</ul>
<p><strong>核心特性：</strong></p>
<ul>
<li class=""><strong>包含日期和时间部分。</strong></li>
<li class=""><strong>包含明确的时区信息：</strong> 它与一个IANA时区标识符（如 "America/New_York"）相关联。</li>
<li class=""><strong>准确无歧义：</strong> 它代表了地球上的一个精确时刻。</li>
<li class=""><strong>自动处理夏令时：</strong> 库会根据指定的时区正确处理夏令时的变化。</li>
<li class=""><strong>支持多种日历系统。</strong></li>
</ul>
<p><strong>示例：</strong></p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> getLocalTimeZone</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">ZonedDateTime</span><span class="token imports"> </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@internationalized/date"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 表示在纽约时区 2025 年 11 月 5 日下午 8 点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> flightDeparture </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ZonedDateTime</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token number" style="color:#36acaa">2025</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token number" style="color:#36acaa">11</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"America/New_York"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token number" style="color:#36acaa">20</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 20 点</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token console class-name">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">flightDeparture</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 输出类似: 2025-11-05T20:00:00-05:00[America/New_York]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 获取用户本地时区的当前时间</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> nowInLocal </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ZonedDateTime</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Date</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getLocalTimeZone</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结与选择指南">总结与选择指南<a href="https://your-docusaurus-site.example.com/differece-among-ZonedDateTime-CalendarDate-CalendarDateTime-Time#%E6%80%BB%E7%BB%93%E4%B8%8E%E9%80%89%E6%8B%A9%E6%8C%87%E5%8D%97" class="hash-link" aria-label="总结与选择指南的直接链接" title="总结与选择指南的直接链接" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">类型</th><th style="text-align:center">包含日期</th><th style="text-align:center">包含时间</th><th style="text-align:center">包含时区</th><th style="text-align:left">适用场景</th></tr></thead><tbody><tr><td style="text-align:left"><strong><code>CalendarDate</code></strong></td><td style="text-align:center">✅</td><td style="text-align:center">❌</td><td style="text-align:center">❌</td><td style="text-align:left">生日、全天事件、不关心具体时间的日期</td></tr><tr><td style="text-align:left"><strong><code>Time</code></strong></td><td style="text-align:center">❌</td><td style="text-align:center">✅</td><td style="text-align:center">❌</td><td style="text-align:left">每日重复的闹钟、营业时间</td></tr><tr><td style="text-align:left"><strong><code>CalendarDateTime</code></strong></td><td style="text-align:center">✅</td><td style="text-align:center">✅</td><td style="text-align:center">❌</td><td style="text-align:left">本地化的日历事件，时间点相对于观察者时区</td></tr><tr><td style="text-align:left"><strong><code>ZonedDateTime</code></strong></td><td style="text-align:center">✅</td><td style="text-align:center">✅</td><td style="text-align:center">✅</td><td style="text-align:left">航班时刻、国际会议、任何需要精确时刻的场景</td></tr></tbody></table>
<p>通过理解这四种类型的不同职责，开发者可以更加精确和可靠地在应用程序中处理各种复杂的日期和时间逻辑，避免由时区和日历系统带来的常见错误。</p>]]></content>
        <author>
            <name>Gemini</name>
            <uri>https://gemini.google.com</uri>
        </author>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="gemini" term="gemini"/>
        <category label="heroui" term="heroui"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[删除 node_modules]]></title>
        <id>https://your-docusaurus-site.example.com/delete-node-modules</id>
        <link href="https://your-docusaurus-site.example.com/delete-node-modules"/>
        <updated>2025-07-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[以下内容均为 Gemini 2.5 Pro 生成]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>以下内容均为 <code>Gemini 2.5 Pro</code> 生成</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="windows-上的-node_modules-黑洞征服路径过长错误">Windows 上的 node_modules 黑洞：征服“路径过长”错误<a href="https://your-docusaurus-site.example.com/delete-node-modules#windows-%E4%B8%8A%E7%9A%84-node_modules-%E9%BB%91%E6%B4%9E%E5%BE%81%E6%9C%8D%E8%B7%AF%E5%BE%84%E8%BF%87%E9%95%BF%E9%94%99%E8%AF%AF" class="hash-link" aria-label="Windows 上的 node_modules 黑洞：征服“路径过长”错误的直接链接" title="Windows 上的 node_modules 黑洞：征服“路径过长”错误的直接链接" translate="no">​</a></h2>
<p>如果你是一名在 Windows 上进行开发的程序员，你很可能遇到过这种情况：那个顽固的 <code>node_modules</code> 文件夹拒绝被删除。你试图将它拖到回收站，却只看到一个令人费解的错误提示。你尝试使用命令行，结果它抱怨路径太长。这种令人沮 જય体验，是 Windows 的一个历史遗留限制与现代网络开发实践猛烈碰撞的直接后果。</p>
<p>这篇博文将深入探讨这个问题的根源——臭名昭著的 <code>MAX_PATH</code> 限制，并介绍两个来自 Node.js 生态系统的强大且对开发者友好的工具——<code>rimraf</code> 和 <code>del-cli</code>，它们可以一劳永逸地解决这个问题。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题的根源windows-256-个字符的阿喀琉斯之踵">问题的根源：Windows 256 个字符的阿喀琉斯之踵<a href="https://your-docusaurus-site.example.com/delete-node-modules#%E9%97%AE%E9%A2%98%E7%9A%84%E6%A0%B9%E6%BA%90windows-256-%E4%B8%AA%E5%AD%97%E7%AC%A6%E7%9A%84%E9%98%BF%E5%96%80%E7%90%89%E6%96%AF%E4%B9%8B%E8%B8%B5" class="hash-link" aria-label="问题的根源：Windows 256 个字符的阿喀琉斯之踵的直接链接" title="问题的根源：Windows 256 个字符的阿喀琉斯之踵的直接链接" translate="no">​</a></h2>
<p>问题的核心在于一个被称为 <code>MAX_PATH</code> 的 Windows API 限制。几十年来，许多核心的 Windows 函数都无法处理超过 260 个字符的文件路径。这包括驱动器号、文件夹、文件名和扩展名。</p>
<p>现代 Node.js 项目及其深度和复杂的依赖树，常常会突破这个限制。像 <code>npm</code> 这样的包管理器解决依赖关系的方式，通常涉及在彼此内部创建层层嵌套的 <code>node_modules</code> 目录。一个构建工具可能会在这个结构的深处创建一个 <code>.cache</code> 文件夹，然后突然之间，一个类似 <code>C:\...\node_modules\A\node_modules\B\.cache\C\...</code> 的文件路径就轻易地超过了 256 个字符的限制。</p>
<p>当这种情况发生时，像 Windows 文件资源管理器这样的标准工具就会直接放弃，无法处理该路径，留给你一个似乎无法删除的文件夹。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="生态系统解决方案以子之矛攻子之盾rimraf-与-del-cli">生态系统解决方案：以子之矛，攻子之盾——rimraf 与 del-cli<a href="https://your-docusaurus-site.example.com/delete-node-modules#%E7%94%9F%E6%80%81%E7%B3%BB%E7%BB%9F%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E4%BB%A5%E5%AD%90%E4%B9%8B%E7%9F%9B%E6%94%BB%E5%AD%90%E4%B9%8B%E7%9B%BErimraf-%E4%B8%8E-del-cli" class="hash-link" aria-label="生态系统解决方案：以子之矛，攻子之盾——rimraf 与 del-cli的直接链接" title="生态系统解决方案：以子之矛，攻子之盾——rimraf 与 del-cli的直接链接" translate="no">​</a></h2>
<p>既然这个问题与 Node.js 生态系统密切相关，那么最合适的解决方案也源于其中。与其依赖晦涩的 Windows 命令，你可以使用专门为克服这些限制而设计的 npm 包。这些工具可以被添加到项目的 <code>package.json</code> 脚本中，为整个团队创建一种一致的、跨平台的项目清理方式。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="rimraf经典的-rm--rf-nodejs-替代品">rimraf：经典的 <code>rm -rf</code> Node.js 替代品<a href="https://your-docusaurus-site.example.com/delete-node-modules#rimraf%E7%BB%8F%E5%85%B8%E7%9A%84-rm--rf-nodejs-%E6%9B%BF%E4%BB%A3%E5%93%81" class="hash-link" aria-label="rimraf经典的-rm--rf-nodejs-替代品的直接链接" title="rimraf经典的-rm--rf-nodejs-替代品的直接链接" translate="no">​</a></h3>
<p><code>rimraf</code> 在 Node.js 世界中家喻户晓。它的名字来源于 Unix/Linux 系统中强大的 <code>rm -rf</code> 命令，并服务于相同的目的：递归地删除文件和目录。</p>
<p><strong>工作原理：</strong> <code>rimraf</code> 使用 Node.js 自己的文件系统（<code>fs</code>）模块进行操作。这些模块在设计上就能处理那些会困扰旧版 Windows shell 的长路径名，使得 <code>rimraf</code> 能够在其他方法失败的地方取得成功。</p>
<p><strong>使用方法：</strong> 最常见和推荐的方式是将其作为项目的开发依赖项安装：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> rimraf --save-dev</span><br></span></code></pre></div></div>
<p>然后，你可以在 <code>package.json</code> 中添加一个脚本：</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">"scripts"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"clean"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"rimraf ./node_modules"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>现在，团队中的任何人只需运行 <code>npm run clean</code>，就可以可靠地删除 <code>node_modules</code> 文件夹，无论他们使用什么操作系统。</p>
<p>尽管 <code>rimraf</code> 非常有效和简单，但它也有其局限性。它的执行速度可能比原生 shell 命令慢，并且在没有额外包的情况下，不支持用于更复杂删除任务的通配符模式（glob）。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="del-cli一个更安全更灵活的替代方案">del-cli：一个更安全、更灵活的替代方案<a href="https://your-docusaurus-site.example.com/delete-node-modules#del-cli%E4%B8%80%E4%B8%AA%E6%9B%B4%E5%AE%89%E5%85%A8%E6%9B%B4%E7%81%B5%E6%B4%BB%E7%9A%84%E6%9B%BF%E4%BB%A3%E6%96%B9%E6%A1%88" class="hash-link" aria-label="del-cli：一个更安全、更灵活的替代方案的直接链接" title="del-cli：一个更安全、更灵活的替代方案的直接链接" translate="no">​</a></h3>
<p><code>del-cli</code> 是 <code>del</code> 包的命令行接口，它被定位为 <code>rimraf</code> 的一个更现代、功能更丰富的替代品。它直接解决了 <code>rimraf</code> 的许多不足之处。</p>
<p><strong>相较于 <code>rimraf</code> 的主要优势：</strong></p>
<ul>
<li class=""><strong>内置通配符支持：</strong> 你可以直接使用通配符模式来删除特定的文件和文件夹，例如 <code>del-cli "dist/**/*.js"</code>。</li>
<li class=""><strong>增强的安全性：</strong> 默认情况下，<code>del-cli</code> 会阻止你意外删除当前工作目录或其父目录——这是 <code>rimraf</code> 所缺乏的安全保障。你必须使用 <code>--force</code> 标志才能执行这类高风险操作。</li>
<li class=""><strong>演练模式（Dry Run）：</strong> <code>del-cli</code> 提供一个 <code>--dry-run</code> 标志，它会显示 <em>将要</em> 被删除的内容，而不会真正执行任何操作。这对于测试脚本和防止灾难性错误至关重要。</li>
</ul>
<p><strong>使用方法：</strong> 安装方式与 <code>rimraf</code> 类似：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> del-cli --save-dev</span><br></span></code></pre></div></div>
<p><code>package.json</code> 中的清理脚本会是这样：</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">"scripts"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"clean"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"del-cli ./node_modules"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p><strong>Windows 用户重要提示：</strong> Windows 的命令提示符有一个内置的 <code>del</code> 命令。为了避免冲突，你必须在脚本中使用完整的 <code>del-cli</code> 命令。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="rimraf-与-del-cli-功能速览">rimraf 与 del-cli 功能速览<a href="https://your-docusaurus-site.example.com/delete-node-modules#rimraf-%E4%B8%8E-del-cli-%E5%8A%9F%E8%83%BD%E9%80%9F%E8%A7%88" class="hash-link" aria-label="rimraf 与 del-cli 功能速览的直接链接" title="rimraf 与 del-cli 功能速览的直接链接" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">特性</th><th style="text-align:left">rimraf</th><th style="text-align:left">del-cli</th></tr></thead><tbody><tr><td style="text-align:left"><strong>核心功能</strong></td><td style="text-align:left">递归删除</td><td style="text-align:left">递归删除</td></tr><tr><td style="text-align:left"><strong>通配符 (Glob) 支持</strong></td><td style="text-align:left">否 (需要额外工具)</td><td style="text-align:left">是 (内置)</td></tr><tr><td style="text-align:left"><strong>安全防护 (CWD)</strong></td><td style="text-align:left">否 (会直接删除)</td><td style="text-align:left">是 (默认禁止)</td></tr><tr><td style="text-align:left"><strong>演练模式 (Dry Run)</strong></td><td style="text-align:left">否</td><td style="text-align:left">是 (<code>--dry-run</code>)</td></tr><tr><td style="text-align:left"><strong>Windows 命令</strong></td><td style="text-align:left"><code>rimraf</code></td><td style="text-align:left"><code>del-cli</code></td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="结论">结论<a href="https://your-docusaurus-site.example.com/delete-node-modules#%E7%BB%93%E8%AE%BA" class="hash-link" aria-label="结论的直接链接" title="结论的直接链接" translate="no">​</a></h2>
<p>尽管 Windows 上的“路径过长”错误是一个令人沮丧的历史遗留问题，但现代开发者工具为我们提供了明确的前进方向。通过将像 <code>rimraf</code> 或 <code>del-cli</code> 这样的包集成到你的项目脚本中，你可以创建一个简单、健壮且跨平台的解决方案。</p>
<p>对于新项目，<code>del-cli</code> 是推荐的选择，因为它具有更优越的安全特性和内置的灵活性。通过将 <code>"clean": "del-cli ./node_modules"</code> 添加到你的 <code>package.json</code> 中，你不仅为自己解决了问题，还创建了一个标准化的、一键式的解决方案，将使你的整个团队免于 <code>node_modules</code> 黑洞带来的头痛。</p>]]></content>
        <author>
            <name>Gemini</name>
            <uri>https://gemini.google.com</uri>
        </author>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="nodejs" term="nodejs"/>
        <category label="node_modules" term="node_modules"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[禁用 SVGR 的 classname 前缀]]></title>
        <id>https://your-docusaurus-site.example.com/disable-svgr-classname-prefix</id>
        <link href="https://your-docusaurus-site.example.com/disable-svgr-classname-prefix"/>
        <updated>2025-07-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[以下内容均为 Gemini 2.5 Pro 生成]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>以下内容均为 <code>Gemini 2.5 Pro</code> 生成</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="告别恼人前缀如何配置-svgr-不再修改-svg-的-classname">告别恼人前缀：如何配置 SVGR 不再修改 SVG 的 className<a href="https://your-docusaurus-site.example.com/disable-svgr-classname-prefix#%E5%91%8A%E5%88%AB%E6%81%BC%E4%BA%BA%E5%89%8D%E7%BC%80%E5%A6%82%E4%BD%95%E9%85%8D%E7%BD%AE-svgr-%E4%B8%8D%E5%86%8D%E4%BF%AE%E6%94%B9-svg-%E7%9A%84-classname" class="hash-link" aria-label="告别恼人前缀：如何配置 SVGR 不再修改 SVG 的 className的直接链接" title="告别恼人前缀：如何配置 SVGR 不再修改 SVG 的 className的直接链接" translate="no">​</a></h2>
<p>在现代前端开发中，尤其是在 React 项目里，将 SVG 作为组件直接导入是一种优雅且高效的方式。强大的 <a href="https://react-svgr.com/" target="_blank" rel="noopener noreferrer" class="">SVGR</a> 工具使得这一切变得轻而易举。但你可能很快会发现一个“小惊喜”：你精心命名的 SVG <code>className</code> 在转换后，被自动加上了 <code>文件名_svg__</code> 这样的前缀。</p>
<p>比如，一个 <code>className="icon-user"</code> 可能会变成 <code>my-icon_svg__icon-user</code>。</p>
<p>虽然这是 SVGR 出于好意做的保护措施，但在某些场景下，我们确实需要原汁原味的类名。今天，我们就来深入探讨这个问题背后的原因，并提供一个清晰的解决方案。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题背后为什么-svgr-要添加前缀">问题背后：为什么 SVGR 要添加前缀？<a href="https://your-docusaurus-site.example.com/disable-svgr-classname-prefix#%E9%97%AE%E9%A2%98%E8%83%8C%E5%90%8E%E4%B8%BA%E4%BB%80%E4%B9%88-svgr-%E8%A6%81%E6%B7%BB%E5%8A%A0%E5%89%8D%E7%BC%80" class="hash-link" aria-label="问题背后：为什么 SVGR 要添加前缀？的直接链接" title="问题背后：为什么 SVGR 要添加前缀？的直接链接" translate="no">​</a></h3>
<p>首先，要明确一点：这不是一个 Bug，而是一个 Feature。</p>
<p>在大型项目中，你可能会从不同的设计师或图标库中引入多个 SVG 文件。这些文件很有可能包含相同的类名，例如 <code>&lt;svg class="icon"&gt;</code>。如果 SVGR 不做任何处理，直接将它们转换成组件，这些相同的类名就会在全局 CSS 环境中产生<strong>样式冲突</strong>或<strong>样式污染</strong>，导致一个组件的样式意外地影响到另一个。</p>
<p>为了避免这种混乱，SVGR 内部集成的优化工具 <strong>SVGO (SVG Optimizer)</strong> 默认启用了一个名为 <code>prefixIds</code> 的插件。这个插件会自动扫描 SVG 内容，并为所有的 <code>id</code> 和 <code>class</code> 名称添加一个基于文件名的唯一前缀，从而确保其在项目中的唯一性。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="解决方案掌控-svgo-配置">解决方案：掌控 SVGO 配置<a href="https://your-docusaurus-site.example.com/disable-svgr-classname-prefix#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E6%8E%8C%E6%8E%A7-svgo-%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="解决方案：掌控 SVGO 配置的直接链接" title="解决方案：掌控 SVGO 配置的直接链接" translate="no">​</a></h3>
<p>既然知道了问题的根源在于 SVGO 的 <code>prefixIds</code> 插件，那么解决方案就很明确了：<strong>覆盖这个插件的默认配置</strong>。</p>
<p>我们可以通过 SVGR 的配置文件，告诉它我们不希望 <code>prefixIds</code> 插件来修改我们的 <code>className</code>。</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="推荐方式使用-svgrconfigjs">推荐方式：使用 <code>svgr.config.js</code><a href="https://your-docusaurus-site.example.com/disable-svgr-classname-prefix#%E6%8E%A8%E8%8D%90%E6%96%B9%E5%BC%8F%E4%BD%BF%E7%94%A8-svgrconfigjs" class="hash-link" aria-label="推荐方式使用-svgrconfigjs的直接链接" title="推荐方式使用-svgrconfigjs的直接链接" translate="no">​</a></h4>
<p>在项目根目录下创建一个独立的配置文件，是管理 SVGR 行为最清晰的方式。</p>
<ol>
<li class="">
<p><strong>创建文件</strong>：在你的项目根目录（与 <code>package.json</code>同级）下创建 <code>svgr.config.js</code> 文件。</p>
</li>
<li class="">
<p><strong>添加配置</strong>：将以下代码复制到文件中。</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// svgr.config.js</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 传递给 SVGO 的配置</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">svgoConfig</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">plugins</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// 插件名称，我们要修改的就是这个</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token literal-property property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"prefixIds"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// 插件参数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token literal-property property" style="color:#36acaa">params</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token comment" style="color:#999988;font-style:italic">// 禁用为 ID 添加前缀</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token literal-property property" style="color:#36acaa">prefixIds</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token comment" style="color:#999988;font-style:italic">// 禁用为 className 添加前缀 (这是解决问题的关键!)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token literal-property property" style="color:#36acaa">prefixClassNames</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>这段配置清晰地告诉 SVGR：“请在运行时，使用我提供的 <code>svgoConfig</code>。对于 <code>prefixIds</code> 这个插件，请将其 <code>prefixClassNames</code> 和 <code>prefixIds</code> 参数都设置为 <code>false</code>。”</p>
</li>
</ol>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="备选方式在-webpack-中配置">备选方式：在 Webpack 中配置<a href="https://your-docusaurus-site.example.com/disable-svgr-classname-prefix#%E5%A4%87%E9%80%89%E6%96%B9%E5%BC%8F%E5%9C%A8-webpack-%E4%B8%AD%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="备选方式：在 Webpack 中配置的直接链接" title="备选方式：在 Webpack 中配置的直接链接" translate="no">​</a></h4>
<p>如果你的项目使用 Webpack 并且已经配置了 <code>@svgr/webpack</code>，你也可以直接在 <code>webpack.config.js</code> 中完成设置。</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// webpack.config.js</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ... 其他 Webpack 配置</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">module</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">rules</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">// ... 其他 rules</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token literal-property property" style="color:#36acaa">test</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token regex regex-source language-regex special-escape escape" style="color:#36acaa">\.</span><span class="token regex regex-source language-regex" style="color:#36acaa">svg</span><span class="token regex regex-source language-regex anchor function" style="color:#d73a49">$</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token literal-property property" style="color:#36acaa">use</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token literal-property property" style="color:#36acaa">loader</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@svgr/webpack"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token literal-property property" style="color:#36acaa">options</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            </span><span class="token comment" style="color:#999988;font-style:italic">// 在 loader 的 options 中直接传入 svgoConfig</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            </span><span class="token literal-property property" style="color:#36acaa">svgoConfig</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                </span><span class="token literal-property property" style="color:#36acaa">plugins</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                        </span><span class="token literal-property property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"prefixIds"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                        </span><span class="token literal-property property" style="color:#36acaa">params</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                            </span><span class="token literal-property property" style="color:#36acaa">prefixIds</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                            </span><span class="token literal-property property" style="color:#36acaa">prefixClassNames</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="使用-rsbuild-配置">使用 rsbuild 配置<a href="https://your-docusaurus-site.example.com/disable-svgr-classname-prefix#%E4%BD%BF%E7%94%A8-rsbuild-%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="使用 rsbuild 配置的直接链接" title="使用 rsbuild 配置的直接链接" translate="no">​</a></h4>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> defineConfig </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@rsbuild/core"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> pluginReact </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@rsbuild/plugin-react"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> pluginSvgr </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@rsbuild/plugin-svgr"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">defineConfig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    plugins</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">pluginReact</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">pluginSvgr</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            svgrOptions</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                exportType</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"default"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                svgoConfig</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    plugins</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"prefixIds"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            params</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                prefixIds</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                prefixClassNames</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>两种方式效果完全相同，选择哪一种取决于你的项目结构和个人偏好。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="重要提醒禁用前缀的潜在风险">重要提醒：禁用前缀的潜在风险<a href="https://your-docusaurus-site.example.com/disable-svgr-classname-prefix#%E9%87%8D%E8%A6%81%E6%8F%90%E9%86%92%E7%A6%81%E7%94%A8%E5%89%8D%E7%BC%80%E7%9A%84%E6%BD%9C%E5%9C%A8%E9%A3%8E%E9%99%A9" class="hash-link" aria-label="重要提醒：禁用前缀的潜在风险的直接链接" title="重要提醒：禁用前缀的潜在风险的直接链接" translate="no">​</a></h3>
<p>当你禁用类名前缀后，避免样式冲突的责任就回到了你的肩上。请确保：</p>
<ol>
<li class=""><strong>命名规范</strong>：在不同的 SVG 文件中，使用具有唯一性的类名。可以采用 BEM (<code>block__element--modifier</code>) 这样的命名约定来降低冲突概率。</li>
<li class=""><strong>CSS 作用域</strong>：使用 CSS Modules, Styled Components, หรือ Tailwind CSS 等技术，它们能从根本上解决全局样式污染的问题。</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://your-docusaurus-site.example.com/disable-svgr-classname-prefix#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h3>
<p>SVGR 默认添加 <code>className</code> 前缀是为了防止样式冲突，是一个贴心的设计。但通过简单的配置，我们可以轻松禁用它，以满足特定的开发需求。核心在于通过 <code>svgoConfig</code> 选项，将 <code>prefixIds</code> 插件的 <code>prefixClassNames</code> 参数设置为 <code>false</code>。</p>
<p>希望这篇文章能帮助你更好地掌控你的 SVG 工作流，写出更干净、更可控的代码。Happy Coding!</p>]]></content>
        <author>
            <name>Gemini</name>
            <uri>https://gemini.google.com</uri>
        </author>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="webpack" term="webpack"/>
        <category label="rsbuild" term="rsbuild"/>
        <category label="svgr" term="svgr"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[回车键提交表单]]></title>
        <id>https://your-docusaurus-site.example.com/form-submit-with-enter</id>
        <link href="https://your-docusaurus-site.example.com/form-submit-with-enter"/>
        <updated>2025-06-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[以下内容均为 Claude 4 sonnet 生成]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>以下内容均为 <code>Claude 4 sonnet</code> 生成</p>
</blockquote>
<p>作为前端开发者，你是否遇到过这样的困惑：有时候在表单输入框中按下 Enter 键会自动提交表单，有时候却没有反应？今天我们就来深入了解一下 HTML 表单中 Enter 键的行为规律。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="神奇的现象">神奇的现象<a href="https://your-docusaurus-site.example.com/form-submit-with-enter#%E7%A5%9E%E5%A5%87%E7%9A%84%E7%8E%B0%E8%B1%A1" class="hash-link" aria-label="神奇的现象的直接链接" title="神奇的现象的直接链接" translate="no">​</a></h2>
<p>让我们先来看几个有趣的例子：</p>
<ul>
<li class="">
<p>单个搜索框</p>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">form</span><span class="token tag" style="color:#00009f"> </span><span class="token tag special-attr attr-name" style="color:#00a4db">onsubmit</span><span class="token tag special-attr attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag special-attr attr-value punctuation" style="color:#393A34">"</span><span class="token tag special-attr attr-value value javascript language-javascript function" style="color:#d73a49">alert</span><span class="token tag special-attr attr-value value javascript language-javascript punctuation" style="color:#393A34">(</span><span class="token tag special-attr attr-value value javascript language-javascript string" style="color:#e3116c">'搜索提交了!'</span><span class="token tag special-attr attr-value value javascript language-javascript punctuation" style="color:#393A34">)</span><span class="token tag special-attr attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">text</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">q</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">请输入搜索关键词</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">form</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<p>在这个搜索框中按Enter键，即使没有提交按钮，表单也会自动提交。</p>
</li>
<li class="">
<p>登录表单（无按钮）</p>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">form</span><span class="token tag" style="color:#00009f"> </span><span class="token tag special-attr attr-name" style="color:#00a4db">onsubmit</span><span class="token tag special-attr attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag special-attr attr-value punctuation" style="color:#393A34">"</span><span class="token tag special-attr attr-value value javascript language-javascript function" style="color:#d73a49">alert</span><span class="token tag special-attr attr-value value javascript language-javascript punctuation" style="color:#393A34">(</span><span class="token tag special-attr attr-value value javascript language-javascript string" style="color:#e3116c">'登录提交了!'</span><span class="token tag special-attr attr-value value javascript language-javascript punctuation" style="color:#393A34">)</span><span class="token tag special-attr attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">text</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">username</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">用户名</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">password</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">password</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">密码</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">form</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<p>在这个表单的任何输入框中按Enter键，什么都不会发生。</p>
</li>
<li class="">
<p>登录表单（有按钮）</p>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">form</span><span class="token tag" style="color:#00009f"> </span><span class="token tag special-attr attr-name" style="color:#00a4db">onsubmit</span><span class="token tag special-attr attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag special-attr attr-value punctuation" style="color:#393A34">"</span><span class="token tag special-attr attr-value value javascript language-javascript function" style="color:#d73a49">alert</span><span class="token tag special-attr attr-value value javascript language-javascript punctuation" style="color:#393A34">(</span><span class="token tag special-attr attr-value value javascript language-javascript string" style="color:#e3116c">'登录提交了!'</span><span class="token tag special-attr attr-value value javascript language-javascript punctuation" style="color:#393A34">)</span><span class="token tag special-attr attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">text</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">username</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">用户名</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">password</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">password</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">密码</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">submit</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">登录</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">form</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
<p>添加了提交按钮后，按Enter键又能正常提交了。</p>
</li>
</ul>
<p>是不是感觉很神奇？这背后其实有着清晰的逻辑。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="规律总结">规律总结<a href="https://your-docusaurus-site.example.com/form-submit-with-enter#%E8%A7%84%E5%BE%8B%E6%80%BB%E7%BB%93" class="hash-link" aria-label="规律总结的直接链接" title="规律总结的直接链接" translate="no">​</a></h2>
<p>HTML 表单的 Enter 键行为遵循以下规律：</p>
<ul>
<li class="">
<p>单输入字段规则</p>
<p>当表单只包含一个文本输入字段时，无论是否有提交按钮，按Enter键都会触发表单提交。这主要是为了优化用户体验，特别是搜索框这类常见场景。</p>
</li>
<li class="">
<p>多输入字段规则</p>
<p>当表单包含多个输入字段时：</p>
<ul>
<li class=""><strong>有提交按钮</strong>：按Enter键会触发提交</li>
<li class=""><strong>无提交按钮</strong>：按Enter键不会触发提交</li>
</ul>
</li>
<li class="">
<p>提交按钮的定义</p>
<p>以下元素都被认为是提交按钮：</p>
<ul>
<li class=""><code>&lt;input type="submit"&gt;</code></li>
<li class=""><code>&lt;button type="submit"&gt;</code></li>
<li class=""><code>&lt;button&gt;</code>（默认type为submit）</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="设计思路">设计思路<a href="https://your-docusaurus-site.example.com/form-submit-with-enter#%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%B7%AF" class="hash-link" aria-label="设计思路的直接链接" title="设计思路的直接链接" translate="no">​</a></h2>
<p>这种看似复杂的行为设计，实际上体现了Web标准制定者的深思熟虑：</p>
<ul>
<li class="">
<p>用户体验优先</p>
<ul>
<li class="">搜索框这类单字段表单支持Enter快速提交，符合用户习惯</li>
<li class="">复杂表单需要明确的提交按钮，避免误操作</li>
</ul>
</li>
<li class="">
<p>渐进增强</p>
<ul>
<li class="">简单功能（搜索）开箱即用</li>
<li class="">复杂功能（多字段表单）需要明确的交互设计</li>
</ul>
</li>
<li class="">
<p>向后兼容</p>
<ul>
<li class="">保持与早期 HTML 标准的兼容性</li>
<li class="">确保现有网站功能正常</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="实际应用建议">实际应用建议<a href="https://your-docusaurus-site.example.com/form-submit-with-enter#%E5%AE%9E%E9%99%85%E5%BA%94%E7%94%A8%E5%BB%BA%E8%AE%AE" class="hash-link" aria-label="实际应用建议的直接链接" title="实际应用建议的直接链接" translate="no">​</a></h2>
<ul>
<li class="">
<p>搜索功能</p>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- 推荐：简洁的搜索表单 --&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">form</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">action</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">/search</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">method</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">GET</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">search</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">q</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">搜索商品</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">form</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>登录/注册表单</p>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- 推荐：明确的提交按钮 --&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">form</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">action</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">/login</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">method</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">POST</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">text</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">username</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">用户名</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">password</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">password</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">密码</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">submit</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">登录</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">form</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>复杂表单</p>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- 推荐：多个操作按钮时明确指定类型 --&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">form</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">action</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">/profile</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">method</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">POST</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">text</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">name</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">姓名</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">email</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">email</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">placeholder</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">邮箱</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">button</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag special-attr attr-name" style="color:#00a4db">onclick</span><span class="token tag special-attr attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag special-attr attr-value punctuation" style="color:#393A34">"</span><span class="token tag special-attr attr-value value javascript language-javascript function" style="color:#d73a49">preview</span><span class="token tag special-attr attr-value value javascript language-javascript punctuation" style="color:#393A34">(</span><span class="token tag special-attr attr-value value javascript language-javascript punctuation" style="color:#393A34">)</span><span class="token tag special-attr attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">预览</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">button</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">submit</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">保存</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">button</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">form</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre></div></div>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="注意事项">注意事项<a href="https://your-docusaurus-site.example.com/form-submit-with-enter#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9" class="hash-link" aria-label="注意事项的直接链接" title="注意事项的直接链接" translate="no">​</a></h2>
<ol>
<li class=""><strong>避免意外提交</strong>：对于复杂表单，确保有明确的提交按钮</li>
<li class=""><strong>用户体验</strong>：搜索类功能应该支持Enter键快速操作</li>
<li class=""><strong>测试充分</strong>：在不同浏览器中测试表单的Enter键行为</li>
<li class=""><strong>无障碍访问</strong>：确保键盘用户能够正常使用表单</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://your-docusaurus-site.example.com/form-submit-with-enter#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>HTML表单的Enter键行为虽然看起来复杂，但背后的逻辑是为了平衡用户体验和功能安全。理解这些规律不仅能帮助我们写出更好的表单，也能避免一些常见的用户体验问题。</p>
<p>下次当你的表单出现意外的Enter键行为时，不妨回想一下这篇文章的内容，相信你会很快找到解决方案！</p>
<hr>
<p><em>希望这篇文章对你有帮助。如果你有其他前端开发的疑问，欢迎继续交流！</em></p>]]></content>
        <author>
            <name>Claude</name>
            <uri>https://claude.ai</uri>
        </author>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="html" term="html"/>
        <category label="enter" term="enter"/>
        <category label="claude" term="claude"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[自托管 Next.js]]></title>
        <id>https://your-docusaurus-site.example.com/self-hosting-next</id>
        <link href="https://your-docusaurus-site.example.com/self-hosting-next"/>
        <updated>2025-06-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[使用 Next.js 开发网站后，在自己的服务器上部署比较麻烦，有两种比较简单的解决方案：]]></summary>
        <content type="html"><![CDATA[<p>使用 <code>Next.js</code> 开发网站后，在自己的服务器上部署比较麻烦，有两种比较简单的解决方案：</p>
<ul>
<li class=""><a href="https://nextjs.org/docs/app/guides/custom-server" target="_blank" rel="noopener noreferrer" class="">自定义服务器</a></li>
<li class=""><a href="https://github.com/vercel/next.js/tree/canary/examples/with-docker" target="_blank" rel="noopener noreferrer" class="">Docker</a></li>
</ul>
<p>第一种不用过多介绍，这里主要介绍第二种方案：</p>
<ol>
<li class="">
<p>在 <code>next.config.ts</code> 中添加 <code>output: "standalone"</code></p>
</li>
<li class="">
<p>安装 <code>Docker</code></p>
</li>
<li class="">
<p>在项目根目录下创建 <code>Dockerfile</code> 文件</p>
<div class="language-dockerfile codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dockerfile codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"># syntax=docker.io/docker/dockerfile:1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">FROM node:22-alpine AS base</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Install dependencies only when needed</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">FROM base AS deps</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">WORKDIR /app</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Install dependencies based on the preferred package manager</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">COPY package.json ./</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">RUN npm install --registry=https://registry.npmmirror.com</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Rebuild the source code only when needed</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">FROM base AS builder</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">WORKDIR /app</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">COPY --from=deps /app/node_modules ./node_modules</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">COPY . .</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Next.js collects completely anonymous telemetry data about general usage.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Learn more here: https://nextjs.org/telemetry</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ENV NEXT_TELEMETRY_DISABLED=1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">RUN npx prisma generate</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">RUN npm run build</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Production image, copy all the files and run next</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">FROM base AS runner</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">WORKDIR /app</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ENV NODE_ENV=production</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Uncomment the following line in case you want to disable telemetry during runtime.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ENV NEXT_TELEMETRY_DISABLED=1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">COPY --from=builder /app/public ./public</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Automatically leverage output traces to reduce image size</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># https://nextjs.org/docs/advanced-features/output-file-tracing</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">COPY --from=builder /app/.next/standalone ./</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">COPY --from=builder /app/.next/static ./.next/static</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">EXPOSE 3000</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ENV PORT=3000</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># server.js is created by next build from the standalone output</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># https://nextjs.org/docs/pages/api-reference/config/next-config-js/output</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ENV HOSTNAME="0.0.0.0"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CMD ["node", "server.js"]</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>在项目根目录下创建 <code>.dockerignore</code> 文件，主要内容应该和 <code>.gitignore</code> 类似，忽略一些不需要的文件，比如 <code>node_modules</code> 和 <code>.next</code> 目录之类的</p>
</li>
<li class="">
<p>在 <code>package.json</code> 中添加 <code>"build:docker": "docker build -t your-app-name ."</code></p>
</li>
</ol>
<p>从 <code>Dockerfile</code> 中可以看出，自托管的核心就是 <code>standalone</code> 模式，这个模式下，<code>Next.js</code> 会生成一个 <code>server.js</code> 文件，这个文件是 <code>Next.js</code> 的入口文件，会自动监听 <code>3000</code> 端口，并启动 <code>Next.js</code> 应用。</p>
<p>其实，本质上最重要的产物就是 <code>.next/standalone</code> 目录，这个目录就是最终的根目录。所以最终目录结构应该是这样的：</p>
<p><code>.next/standalone</code> → <code>app</code></p>
<p><code>.next/static</code> → <code>app/.next/static</code></p>
<p><code>public</code> → <code>app/public</code></p>
<p>只要明白了这个原理，我们就可以再实现一个 <code>Next.js</code> 的“安装”程序：</p>
<p>在项目根目录下创建一个 <code>scripts/createInstaller.ts</code> 文件，内容如下：</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> readdir</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> rm</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> writeFile </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"fs/promises"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> resolve </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"path"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> spawnAsync</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> zip </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"soda-nodejs"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> reg </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token regex regex-source language-regex anchor function" style="color:#d73a49">^</span><span class="token regex regex-source language-regex" style="color:#36acaa">--target=</span><span class="token regex regex-source language-regex group punctuation" style="color:#393A34">(</span><span class="token regex regex-source language-regex" style="color:#36acaa">windows</span><span class="token regex regex-source language-regex alternation keyword" style="color:#00009f">|</span><span class="token regex regex-source language-regex" style="color:#36acaa">linux</span><span class="token regex regex-source language-regex group punctuation" style="color:#393A34">)</span><span class="token regex regex-source language-regex anchor function" style="color:#d73a49">$</span><span class="token regex regex-delimiter" style="color:#36acaa">/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> target </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">argv</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">find</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> reg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">test</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?.</span><span class="token function" style="color:#d73a49">match</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">reg</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?.</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">??</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"windows"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"windows"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"linux"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">rm</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"scripts/install.ts"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> force</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">spawnAsync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"bunx prisma generate"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> shell</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> stdio</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"inherit"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">spawnAsync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"bun run build:standalone"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> shell</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> stdio</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"inherit"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> input </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">readdir</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">".next/standalone"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">zip</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> input</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> output</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"../standalone.zip"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cwd</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">".next/standalone"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> input2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">readdir</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">".next/static"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">zip</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> input</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> input2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> output</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"../static.zip"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cwd</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">".next/static"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> input3 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">readdir</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"public"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">zip</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> input</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> input3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> output</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"../.next/public.zip"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cwd</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"public"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> script </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">import { mkdir, readFile, readdir, rename, rm, stat, writeFile } from "fs/promises"</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">import { join, parse, resolve } from "path"</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">import { Readable } from "stream"</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">import { ReadableStream } from "stream/web"</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">import { styleText } from "util"</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">import { file } from "bun"</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">import { unzip } from "soda-nodejs"</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">import publicPath from "../.next/public.zip" with { type: "file" }</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">import standalonePath from "../.next/standalone.zip" with { type: "file" }</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">import staticPath from "../.next/static.zip" with { type: "file" }</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c"></span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">target </span><span class="token template-string interpolation operator" style="color:#393A34">===</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation string" style="color:#e3116c">"windows"</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation operator" style="color:#393A34">?</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation template-string string" style="color:#e3116c">import windowsPath from "../prisma/generated/query_engine-windows.dll.node" with { type: "file" }</span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation operator" style="color:#393A34">:</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation template-string string" style="color:#e3116c">import debianPath from "../prisma/generated/libquery_engine-debian-openssl-3.0.x.so.node" with { type: "file" }</span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">const from = \`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation function" style="color:#d73a49">resolve</span><span class="token template-string interpolation punctuation" style="color:#393A34">(</span><span class="token template-string interpolation string" style="color:#e3116c">"."</span><span class="token template-string interpolation punctuation" style="color:#393A34">)</span><span class="token template-string interpolation punctuation" style="color:#393A34">.</span><span class="token template-string interpolation function" style="color:#d73a49">replace</span><span class="token template-string interpolation punctuation" style="color:#393A34">(</span><span class="token template-string interpolation regex regex-delimiter" style="color:#36acaa">/</span><span class="token template-string interpolation regex regex-source language-regex special-escape escape" style="color:#36acaa">\\</span><span class="token template-string interpolation regex regex-delimiter" style="color:#36acaa">/</span><span class="token template-string interpolation regex regex-flags" style="color:#36acaa">g</span><span class="token template-string interpolation punctuation" style="color:#393A34">,</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation string" style="color:#e3116c">"\\\\"</span><span class="token template-string interpolation punctuation" style="color:#393A34">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c">\`.replace(/[\\\\/]$/, "")</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">const to = resolve(".").replace(/^[a-zA-Z]+/, m =&gt; m.toUpperCase()).replace(/[\\\\/]$/, "")</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">const from2 = encodeURIComponent(from)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">const to2 = encodeURIComponent(to)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">const from3 = encodeURIComponent(from + "/")</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">const to3 = encodeURIComponent(to + "/")</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">const from4 = encodeURIComponent(from + "\\\\")</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">const to4 = encodeURIComponent(to + "\\\\")</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">function escapeRegExp(str: string) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    return str.replace(/[.*+?^\${}()|[\\]\\\\]/g, "\\\\$&amp;")</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">const reg = new RegExp(</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    \`\${escapeRegExp(from.replace(/[\\\\/]/g, "__PLACEHOLDER__")).replace(/__PLACEHOLDER__/g, "\\\\\\\\{0,3}[\\\\\\\\/]")}(\\\\\\\\{0,3}[\\\\\\\\/])?\`,</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    "gi",</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">async function replacePath(dir: string) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    const { name } = parse(dir)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    if (name === "node_modules") return</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    const files = await readdir(dir)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    for (const file of files) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">        const path = join(dir, file)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">        const status = await stat(path)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">        if (status.isDirectory()) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">            await replacePath(path)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">        } else {</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">            if (/\\.([mc]?js|json)$/i.test(path)) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">                const content = await readFile(path, "utf-8")</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">                const newContent = content</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">                    .replace(reg, (m, p) =&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">                        const prefix = m.match(/(\\\\{0,3})[\\\\/]/)?.[1] ?? ""</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">                        const split = \`\${prefix}\${m.includes("/") ? "/" : "\\\\"}\`</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">                        return \`\${to.replace(/[\\\\/]/g, split)}\${p ? split : ""}\`</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">                    })</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">                    .replaceAll(from2, to2)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">                    .replaceAll(from3, to3)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">                    .replaceAll(from4, to4)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">                await writeFile(path, newContent)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">            }</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">async function main() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    const publicStream = Readable.fromWeb(file(publicPath).stream() as ReadableStream)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    const standaloneStream = Readable.fromWeb(file(standalonePath).stream() as ReadableStream)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    const staticStream = Readable.fromWeb(file(staticPath).stream() as ReadableStream)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">target </span><span class="token template-string interpolation operator" style="color:#393A34">===</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation string" style="color:#e3116c">"windows"</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation operator" style="color:#393A34">?</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation template-string string" style="color:#e3116c">const windowsStream = Readable.fromWeb(file(windowsPath).stream() as ReadableStream)</span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation operator" style="color:#393A34">:</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation template-string string" style="color:#e3116c">const debianStream = Readable.fromWeb(file(debianPath).stream() as ReadableStream)</span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await rm(".temp", { recursive: true, force: true })</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await mkdir(".temp", { recursive: true })</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await writeFile(".temp/public.zip", publicStream)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await writeFile(".temp/standalone.zip", standaloneStream)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await writeFile(".temp/static.zip", staticStream)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await unzip({ input: ".temp/public.zip", output: ".temp/public" })</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await unzip({ input: ".temp/standalone.zip", output: ".temp/standalone" })</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await unzip({ input: ".temp/static.zip", output: ".temp/static" })</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    const dir = await readdir(".temp/standalone")</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    for (const item of dir) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">        await rm(item, { recursive: true, force: true })</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">        await rename(\`.temp/standalone/\${item}\`, item)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await rm("public", { recursive: true, force: true })</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await rename(".temp/public", "public")</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await rm(".next/static", { recursive: true, force: true })</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await rename(".temp/static", ".next/static")</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await replacePath(to)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await mkdir("prisma/generated", { recursive: true })</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">target </span><span class="token template-string interpolation operator" style="color:#393A34">===</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation string" style="color:#e3116c">"windows"</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation operator" style="color:#393A34">?</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation template-string string" style="color:#e3116c">writeFile("prisma/generated/query_engine-windows.dll.node", windowsStream)</span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation operator" style="color:#393A34">:</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation template-string string" style="color:#e3116c">writeFile("prisma/generated/libquery_engine-debian-openssl-3.0.x.so.node", debianStream)</span><span class="token template-string interpolation template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    await rm(".temp", { recursive: true, force: true })</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    console.log(styleText("greenBright", "Task completed, the program will exit in 3 seconds..."))</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">    setTimeout(() =&gt; 0, 3000)</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="display:inline-block;color:#e3116c"></span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">main()</span><br></span><span class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c"></span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">writeFile</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"scripts/install.ts"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> script</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">spawnAsync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">bun build --compile --target=bun-</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">target</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c">-x64 --minify --sourcemap --bytecode scripts/install.ts --outfile installer</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    shell</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    stdio</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"inherit"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">rm</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"scripts/install.ts"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> force</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">rm</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">".next/standalone.zip"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> force</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">rm</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">".next/static.zip"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> force</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">rm</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">".next/public.zip"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> force</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>在 <code>package.json</code> 中添加以下命令：</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"scripts"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"build:standalone"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"npx cross-env NEXT_OUTPUT=standalone next build"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"build:windows"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"bun scripts/createInstaller.ts --target=windows"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"build:linux"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"bun scripts/createInstaller.ts --target=linux"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>因为我的项目中涉及到 <code>Prisma</code> ，所以需要生成 <code>Prisma</code> 的客户端，所以需要先执行 <code>prisma generate</code> 命令，然后执行 <code>build:standalone</code> 命令，生成 <code>standalone</code> 模式下的 <code>Next.js</code> 应用。又因为最终的平台涉及 <code>Windows</code> 和 <code>Linux</code> ，所以需要生成两个版本的 <code>.node</code> 文件，需要在 <code>schema.prisma</code> 中添加如下内容：</p>
<div class="language-prisma codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-prisma codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">generator client {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    binaryTargets          = ["windows", "debian-openssl-3.0.x"]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>原理也很简单，就是将产物都使用 <code>bun</code> 打包，执行时再释放出来。</p>]]></content>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="Next.js" term="Next.js"/>
        <category label="docker" term="docker"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[在 Prisma 中创建一对一映射关系]]></title>
        <id>https://your-docusaurus-site.example.com/create-a-one-to-one-mapping-relationship-in-prisma</id>
        <link href="https://your-docusaurus-site.example.com/create-a-one-to-one-mapping-relationship-in-prisma"/>
        <updated>2025-06-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[在 Prisma 中，创建一对一映射关系非常简单。只需要在 schema.prisma 文件中添加以下代码：]]></summary>
        <content type="html"><![CDATA[<p>在 <code>Prisma</code> 中，创建一对一映射关系非常简单。只需要在 <code>schema.prisma</code> 文件中添加以下代码：</p>
<div class="language-prisma codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-prisma codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">model User {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    id               String    @id @default(uuid())</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name             String</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    profiles         Profile[] @relation("UserProfile")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    currentProfileId String?   @unique</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    currentProfile   Profile?  @relation("CurrentProfile", fields: [currentProfileId], references: [id])</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">model Profile {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    id          String @id @default(uuid())</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    name        String</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    userId      String</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    user        User   @relation("UserProfile", fields: [userId], references: [id])</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    currentUser User?  @relation("CurrentProfile")</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>]]></content>
        <author>
            <name>1adybug</name>
            <uri>https://github.com/1adybug</uri>
        </author>
        <category label="prisma" term="prisma"/>
        <category label="database" term="database"/>
        <category label="relationship" term="relationship"/>
    </entry>
</feed>