{
    "version": "https://jsonfeed.org/version/1",
    "title": "老王",
    "home_page_url": "https://老王.me/blog",
    "description": "feedId:41215011978385457+userId:41840354283324416",
    "items": [
        {
            "id": "https://老王.me/blog/ts-tutorial",
            "content_html": "<p>本教程面向零基础或刚接触 TypeScript 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"一typescript-简介\">一、TypeScript 简介<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E4%B8%80typescript-%E7%AE%80%E4%BB%8B\" class=\"hash-link\" aria-label=\"一、TypeScript 简介的直接链接\" title=\"一、TypeScript 简介的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"什么是-typescript\">什么是 TypeScript？<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E4%BB%80%E4%B9%88%E6%98%AF-typescript\" class=\"hash-link\" aria-label=\"什么是 TypeScript？的直接链接\" title=\"什么是 TypeScript？的直接链接\">​</a></h3>\n<p>TypeScript 是 JavaScript 的超集，核心是为代码增加 <strong>静态类型</strong>。它能在你运行之前就发现很多类型错误，从而提升代码可靠性与可维护性。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"为什么需要-typescript\">为什么需要 TypeScript？<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81-typescript\" class=\"hash-link\" aria-label=\"为什么需要 TypeScript？的直接链接\" title=\"为什么需要 TypeScript？的直接链接\">​</a></h3>\n<ul>\n<li>提高开发时的提示与可发现性（IDE 体验更好）</li>\n<li>更早暴露类型相关 bug</li>\n<li>更易重构和维护大型工程</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"二环境与安装\">二、环境与安装<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E4%BA%8C%E7%8E%AF%E5%A2%83%E4%B8%8E%E5%AE%89%E8%A3%85\" class=\"hash-link\" aria-label=\"二、环境与安装的直接链接\" title=\"二、环境与安装的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"安装-typescript\">安装 TypeScript<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E5%AE%89%E8%A3%85-typescript\" class=\"hash-link\" aria-label=\"安装 TypeScript的直接链接\" title=\"安装 TypeScript的直接链接\">​</a></h3>\n<p>在项目目录中初始化：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mkdir</span><span class=\"token plain\"> my-ts-app</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> my-ts-app</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> init </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-y</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>安装 TypeScript：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> i </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-D</span><span class=\"token plain\"> typescript</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">npx tsc </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--version</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"初始化-tsconfigjson\">初始化 tsconfig.json<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E5%88%9D%E5%A7%8B%E5%8C%96-tsconfigjson\" class=\"hash-link\" aria-label=\"初始化 tsconfig.json的直接链接\" title=\"初始化 tsconfig.json的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">npx tsc </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--init</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p><code>tsconfig.json</code> 用于配置编译选项（如 <code>target</code>、<code>module</code>、是否开启严格模式等）。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"三类型系统入门\">三、类型系统入门<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E4%B8%89%E7%B1%BB%E5%9E%8B%E7%B3%BB%E7%BB%9F%E5%85%A5%E9%97%A8\" class=\"hash-link\" aria-label=\"三、类型系统入门的直接链接\" title=\"三、类型系统入门的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"基本类型\">基本类型<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B\" class=\"hash-link\" aria-label=\"基本类型的直接链接\" title=\"基本类型的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">let</span><span class=\"token plain\"> name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Alice'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">let</span><span class=\"token plain\"> age</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">number</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">18</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">let</span><span class=\"token plain\"> isOk</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">boolean</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">let</span><span class=\"token plain\"> nothing</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">let</span><span class=\"token plain\"> undef</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">undefined</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">undefined</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">let</span><span class=\"token plain\"> anyValue</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">any</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">123</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">let</span><span class=\"token plain\"> unknownValue</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">unknown</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'text'</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>其中：</p>\n<ul>\n<li><code>any</code>：不做类型约束（慎用）</li>\n<li><code>unknown</code>：未知类型，使用前需要判断</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"联合类型与类型收窄\">联合类型与类型收窄<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B%E4%B8%8E%E7%B1%BB%E5%9E%8B%E6%94%B6%E7%AA%84\" class=\"hash-link\" aria-label=\"联合类型与类型收窄的直接链接\" title=\"联合类型与类型收窄的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">formatId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">number</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">typeof</span><span class=\"token plain\"> id </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">===</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'number'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token template-string template-punctuation string\" style=\"color:hsl(119, 34%, 47%)\">`</span><span class=\"token template-string string\" style=\"color:hsl(119, 34%, 47%)\">#</span><span class=\"token template-string interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">${</span><span class=\"token template-string interpolation\">id</span><span class=\"token template-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token template-string interpolation function\" style=\"color:hsl(221, 87%, 60%)\">toFixed</span><span class=\"token template-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token template-string interpolation number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token template-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token template-string interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token template-string template-punctuation string\" style=\"color:hsl(119, 34%, 47%)\">`</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token template-string template-punctuation string\" style=\"color:hsl(119, 34%, 47%)\">`</span><span class=\"token template-string string\" style=\"color:hsl(119, 34%, 47%)\">#</span><span class=\"token template-string interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">${</span><span class=\"token template-string interpolation\">id</span><span class=\"token template-string interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token template-string template-punctuation string\" style=\"color:hsl(119, 34%, 47%)\">`</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"四接口与类型别名\">四、接口与类型别名<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E5%9B%9B%E6%8E%A5%E5%8F%A3%E4%B8%8E%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D\" class=\"hash-link\" aria-label=\"四、接口与类型别名的直接链接\" title=\"四、接口与类型别名的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"接口interface\">接口（interface）<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E6%8E%A5%E5%8F%A3interface\" class=\"hash-link\" aria-label=\"接口（interface）的直接链接\" title=\"接口（interface）的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">interface</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">User</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  email</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"类型别名type\">类型别名（type）<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8Dtype\" class=\"hash-link\" aria-label=\"类型别名（type）的直接链接\" title=\"类型别名（type）的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">type</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">Point</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  x</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">number</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  y</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">number</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>它们都能描述对象结构，实际项目中可以按团队习惯选择使用。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"五泛型与高级类型\">五、泛型与高级类型<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E4%BA%94%E6%B3%9B%E5%9E%8B%E4%B8%8E%E9%AB%98%E7%BA%A7%E7%B1%BB%E5%9E%8B\" class=\"hash-link\" aria-label=\"五、泛型与高级类型的直接链接\" title=\"五、泛型与高级类型的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"泛型函数\">泛型函数<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E6%B3%9B%E5%9E%8B%E5%87%BD%E6%95%B0\" class=\"hash-link\" aria-label=\"泛型函数的直接链接\" title=\"泛型函数的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token generic-function function\" style=\"color:hsl(221, 87%, 60%)\">wrap</span><span class=\"token generic-function generic class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token generic-function generic class-name constant\" style=\"color:hsl(35, 99%, 36%)\">T</span><span class=\"token generic-function generic class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">value</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token constant\" style=\"color:hsl(35, 99%, 36%)\">T</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> value </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> res </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">wrap</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">123</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// T = number</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"工具类型内置\">工具类型（内置）<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E5%B7%A5%E5%85%B7%E7%B1%BB%E5%9E%8B%E5%86%85%E7%BD%AE\" class=\"hash-link\" aria-label=\"工具类型（内置）的直接链接\" title=\"工具类型（内置）的直接链接\">​</a></h3>\n<p>常见工具类型：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">type</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">PartialUser</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> Partial</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">User</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">type</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">ReadonlyUser</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> Readonly</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">User</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">type</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">PickUser</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> Pick</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">User</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'id'</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'name'</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">type</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">RecordMap</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> Record</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">number</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"六类与模块\">六、类与模块<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E5%85%AD%E7%B1%BB%E4%B8%8E%E6%A8%A1%E5%9D%97\" class=\"hash-link\" aria-label=\"六、类与模块的直接链接\" title=\"六、类与模块的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"类class\">类（class）<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E7%B1%BBclass\" class=\"hash-link\" aria-label=\"类（class）的直接链接\" title=\"类（class）的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">Person</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">constructor</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">public</span><span class=\"token plain\"> name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sayHello</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token template-string template-punctuation string\" style=\"color:hsl(119, 34%, 47%)\">`</span><span class=\"token template-string string\" style=\"color:hsl(119, 34%, 47%)\">hello, </span><span class=\"token template-string interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">${</span><span class=\"token template-string interpolation keyword\" style=\"color:hsl(301, 63%, 40%)\">this</span><span class=\"token template-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token template-string interpolation\">name</span><span class=\"token template-string interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token template-string template-punctuation string\" style=\"color:hsl(119, 34%, 47%)\">`</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"模块import--export\">模块（import / export）<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E6%A8%A1%E5%9D%97import--export\" class=\"hash-link\" aria-label=\"模块（import / export）的直接链接\" title=\"模块（import / export）的直接链接\">​</a></h3>\n<p><code>src/user.ts</code>：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">interface</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">User</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p><code>src/main.ts</code>：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">type</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> User </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./user'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> u</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> User </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'1'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Alice'</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">console</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">log</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">u</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"七编译与-tsconfig\">七、编译与 tsconfig<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E4%B8%83%E7%BC%96%E8%AF%91%E4%B8%8E-tsconfig\" class=\"hash-link\" aria-label=\"七、编译与 tsconfig的直接链接\" title=\"七、编译与 tsconfig的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"基本编译命令\">基本编译命令<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E5%9F%BA%E6%9C%AC%E7%BC%96%E8%AF%91%E5%91%BD%E4%BB%A4\" class=\"hash-link\" aria-label=\"基本编译命令的直接链接\" title=\"基本编译命令的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">npx tsc</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>常用的方式是在 <code>package.json</code> 配置脚本：</p>\n<div class=\"language-json codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-json codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"scripts\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"build\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"tsc -p tsconfig.json\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"严格模式建议逐步开启\">严格模式（建议逐步开启）<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E4%B8%A5%E6%A0%BC%E6%A8%A1%E5%BC%8F%E5%BB%BA%E8%AE%AE%E9%80%90%E6%AD%A5%E5%BC%80%E5%90%AF\" class=\"hash-link\" aria-label=\"严格模式（建议逐步开启）的直接链接\" title=\"严格模式（建议逐步开启）的直接链接\">​</a></h3>\n<p><code>tsconfig.json</code> 中常见选项：</p>\n<ul>\n<li><code>strict</code>：开启一组严格检查</li>\n<li><code>noImplicitAny</code>：禁止隐式 <code>any</code></li>\n</ul>\n<p>新手建议不要一口气全开，但可以从最基础的开始。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"八与-nodejs-结合express-示例ts\">八、与 Node.js 结合：Express 示例（TS）<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E5%85%AB%E4%B8%8E-nodejs-%E7%BB%93%E5%90%88express-%E7%A4%BA%E4%BE%8Bts\" class=\"hash-link\" aria-label=\"八、与 Node.js 结合：Express 示例（TS）的直接链接\" title=\"八、与 Node.js 结合：Express 示例（TS）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"安装依赖\">安装依赖<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E5%AE%89%E8%A3%85%E4%BE%9D%E8%B5%96\" class=\"hash-link\" aria-label=\"安装依赖的直接链接\" title=\"安装依赖的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> i express</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> i </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-D</span><span class=\"token plain\"> @types/express ts-node nodemon</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>创建 <code>src/server.ts</code>：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> express </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'express'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> app </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">express</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">use</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">express</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">get</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'/health'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">_req</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> ok</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">post</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'/echo'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">req</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> received</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> req</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">body </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">listen</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3000</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">console</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">log</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'server running at http://localhost:3000'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>启动（开发模式）：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">nodemon </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--exec</span><span class=\"token plain\"> ts-node src/server.ts</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"九常见工程化lintformat\">九、常见工程化：lint/format<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E4%B9%9D%E5%B8%B8%E8%A7%81%E5%B7%A5%E7%A8%8B%E5%8C%96lintformat\" class=\"hash-link\" aria-label=\"九、常见工程化：lint/format的直接链接\" title=\"九、常见工程化：lint/format的直接链接\">​</a></h2>\n<p>工程化不是“越多越好”，但至少应做到：</p>\n<ul>\n<li>统一格式（Prettier）</li>\n<li>基于类型的检查与规则（ESLint + TypeScript）</li>\n</ul>\n<p>你可以先从 <code>prettier</code> 开始，后续再加 ESLint。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十测试与构建\">十、测试与构建<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E5%8D%81%E6%B5%8B%E8%AF%95%E4%B8%8E%E6%9E%84%E5%BB%BA\" class=\"hash-link\" aria-label=\"十、测试与构建的直接链接\" title=\"十、测试与构建的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"测试思路\">测试思路<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E6%B5%8B%E8%AF%95%E6%80%9D%E8%B7%AF\" class=\"hash-link\" aria-label=\"测试思路的直接链接\" title=\"测试思路的直接链接\">​</a></h3>\n<p>常用方案：</p>\n<ul>\n<li>单元测试：Jest / Vitest</li>\n<li>集成测试：supertest（Express）</li>\n</ul>\n<p>这里建议你先跑通：</p>\n<ol>\n<li>把业务逻辑从路由中抽离成函数</li>\n<li>对函数进行单测</li>\n</ol>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十一最佳实践与小结\">十一、最佳实践与小结<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E5%8D%81%E4%B8%80%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%E4%B8%8E%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"十一、最佳实践与小结的直接链接\" title=\"十一、最佳实践与小结的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"最佳实践\">最佳实践<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5\" class=\"hash-link\" aria-label=\"最佳实践的直接链接\" title=\"最佳实践的直接链接\">​</a></h3>\n<ul>\n<li>尽量使用明确的类型（至少在边界：入参出参）</li>\n<li>使用泛型提升复用</li>\n<li>开启 <code>strict</code>（或逐步开启相关严格选项）</li>\n<li>把业务逻辑拆分成可测试的模块</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"小结\">小结<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"小结的直接链接\" title=\"小结的直接链接\">​</a></h3>\n<ul>\n<li>TypeScript 通过类型系统增强可靠性</li>\n<li>接口、类型别名、联合类型与泛型是核心能力</li>\n<li>tsconfig 决定编译策略</li>\n<li>与 Node.js 结合可直接构建 API（Express 示例）</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十二学习路径小结\">十二、学习路径小结<a href=\"https://xn--qbyt9x.me/blog/ts-tutorial#%E5%8D%81%E4%BA%8C%E5%AD%A6%E4%B9%A0%E8%B7%AF%E5%BE%84%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"十二、学习路径小结的直接链接\" title=\"十二、学习路径小结的直接链接\">​</a></h2>\n<ol>\n<li>跑通 <code>tsc</code> 编译流程，理解输出与模块形式</li>\n<li>掌握基础类型、联合类型与类型收窄</li>\n<li>学会接口、泛型与常见工具类型</li>\n<li>结合 Express 写一个最小 API</li>\n<li>从抽离业务逻辑开始加测试，逐步形成工程习惯</li>\n</ol>\n<p>遇到问题可查阅 <a href=\"https://www.typescriptlang.org/docs/handbook/intro.html\" target=\"_blank\" rel=\"noopener noreferrer\">TypeScript 官方文档</a>。</p>",
            "url": "https://老王.me/blog/ts-tutorial",
            "title": "TypeScript 完整教程（新手向）",
            "summary": "由浅入深学习 TypeScript，覆盖类型系统、接口与泛型、工程化（tsconfig/构建）、与 Node.js 结合开发 API 等主要知识点。",
            "date_modified": "2026-03-19T15:11:56.000Z",
            "tags": []
        },
        {
            "id": "https://老王.me/blog/nextjs-tutorial",
            "content_html": "<p>本教程面向零基础或刚接触 Next.js 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"一nextjs-简介\">一、Next.js 简介<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E4%B8%80nextjs-%E7%AE%80%E4%BB%8B\" class=\"hash-link\" aria-label=\"一、Next.js 简介的直接链接\" title=\"一、Next.js 简介的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"什么是-nextjs\">什么是 Next.js？<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E4%BB%80%E4%B9%88%E6%98%AF-nextjs\" class=\"hash-link\" aria-label=\"什么是 Next.js？的直接链接\" title=\"什么是 Next.js？的直接链接\">​</a></h3>\n<p>Next.js 是一个基于 React 的 Web 框架，提供了路由、渲染与构建能力，让你更容易构建：</p>\n<ul>\n<li>SSR / SSG / 混合渲染应用</li>\n<li>全栈 Web（配合 API / Route Handler）</li>\n<li>类型友好的工程化开发体验</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"适合做什么\">适合做什么？<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E9%80%82%E5%90%88%E5%81%9A%E4%BB%80%E4%B9%88\" class=\"hash-link\" aria-label=\"适合做什么？的直接链接\" title=\"适合做什么？的直接链接\">​</a></h3>\n<ul>\n<li>个人博客 / 技术文章站</li>\n<li>产品官网与落地页</li>\n<li>带用户登录、后台管理的 Web 应用（配合你选择的认证方案）</li>\n<li>API 与前后端一体化项目</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"二环境准备与创建项目\">二、环境准备与创建项目<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E4%BA%8C%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87%E4%B8%8E%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"二、环境准备与创建项目的直接链接\" title=\"二、环境准备与创建项目的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"环境要求\">环境要求<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E7%8E%AF%E5%A2%83%E8%A6%81%E6%B1%82\" class=\"hash-link\" aria-label=\"环境要求的直接链接\" title=\"环境要求的直接链接\">​</a></h3>\n<ul>\n<li><strong>Node.js</strong>：建议使用 18.x 及以上（推荐 20 LTS）</li>\n<li>了解基础的 npm/pnpm/yarn 使用</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"创建项目\">创建项目<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"创建项目的直接链接\" title=\"创建项目的直接链接\">​</a></h3>\n<p>使用官方推荐的脚手架 <code>create-next-app</code>：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">npx create-next-app@latest my-next-app</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>初始化安装完成后进入目录并启动：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> my-next-app</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>浏览器打开 <code>http://localhost:3000</code> 即可。</p>\n<div class=\"theme-admonition theme-admonition-tip admonition_fh9h alert alert--success\"><div class=\"admonitionHeading__rZX\"><span class=\"admonitionIcon_krpS\"><svg viewBox=\"0 0 12 16\"><path fill-rule=\"evenodd\" d=\"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z\"></path></svg></span>新手提示</div><div class=\"admonitionContent_oz3Y\"><p>如果你在 WSL / 远程环境访问开发服务器，可能需要让 Next.js 监听所有网卡（或通过端口转发访问）。</p></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"三app-router推荐与基础目录结构\">三、App Router（推荐）与基础目录结构<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E4%B8%89app-router%E6%8E%A8%E8%8D%90%E4%B8%8E%E5%9F%BA%E7%A1%80%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84\" class=\"hash-link\" aria-label=\"三、App Router（推荐）与基础目录结构的直接链接\" title=\"三、App Router（推荐）与基础目录结构的直接链接\">​</a></h2>\n<p>Next.js（新版本）通常使用 <strong>App Router</strong>。常见目录结构如下：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">my-next-app/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── app/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── layout.tsx</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── page.tsx</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   └── api/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│       └── health/route.ts</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── public/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── src/ (可选：把组件/业务逻辑放这里)</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── package.json</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">└── next.config.js</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>关键约定：</p>\n<ul>\n<li><code>app/layout.tsx</code>：全站的根布局（所有页面都会套在里面）</li>\n<li><code>app/page.tsx</code>：<code>/</code> 路由对应的页面</li>\n<li><code>app/**/page.tsx</code>：<code>app</code> 下的每个文件夹可对应一个路由</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"四路由与页面page--layout\">四、路由与页面（Page / Layout）<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E5%9B%9B%E8%B7%AF%E7%94%B1%E4%B8%8E%E9%A1%B5%E9%9D%A2page--layout\" class=\"hash-link\" aria-label=\"四、路由与页面（Page / Layout）的直接链接\" title=\"四、路由与页面（Page / Layout）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"页面pagetsx\">页面：page.tsx<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E9%A1%B5%E9%9D%A2pagetsx\" class=\"hash-link\" aria-label=\"页面：page.tsx的直接链接\" title=\"页面：page.tsx的直接链接\">​</a></h3>\n<p>创建一个路由 <code>app/about/page.tsx</code>：</p>\n<div class=\"language-tsx codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-tsx codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// app/about/page.tsx</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">default</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">AboutPage</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">main</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">      </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">h1</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\">About</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">h1</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">      </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">p</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\">这是一个 /about 页面。</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">p</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">    </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">main</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"链接link\">链接：Link<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E9%93%BE%E6%8E%A5link\" class=\"hash-link\" aria-label=\"链接：Link的直接链接\" title=\"链接：Link的直接链接\">​</a></h3>\n<p>使用 Next.js 的 <code>Link</code> 进行跳转（推荐）：</p>\n<div class=\"language-tsx codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-tsx codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token imports maybe-class-name\">Link</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'next/link'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">default</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Home</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">main</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">      </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">h1</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\">Home</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">h1</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">      </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag class-name\" style=\"color:hsl(35, 99%, 36%)\">Link</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token tag attr-name\" style=\"color:hsl(35, 99%, 36%)\">href</span><span class=\"token tag attr-value punctuation attr-equals\" style=\"color:hsl(119, 34%, 47%)\">=</span><span class=\"token tag attr-value punctuation\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token tag attr-value\" style=\"color:hsl(119, 34%, 47%)\">/about</span><span class=\"token tag attr-value punctuation\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\">去 About</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag class-name\" style=\"color:hsl(35, 99%, 36%)\">Link</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">    </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">main</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"五组件与样式css-modules--全局样式\">五、组件与样式（CSS Modules / 全局样式）<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E4%BA%94%E7%BB%84%E4%BB%B6%E4%B8%8E%E6%A0%B7%E5%BC%8Fcss-modules--%E5%85%A8%E5%B1%80%E6%A0%B7%E5%BC%8F\" class=\"hash-link\" aria-label=\"五、组件与样式（CSS Modules / 全局样式）的直接链接\" title=\"五、组件与样式（CSS Modules / 全局样式）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"css-modules\">CSS Modules<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#css-modules\" class=\"hash-link\" aria-label=\"CSS Modules的直接链接\" title=\"CSS Modules的直接链接\">​</a></h3>\n<p>假设你有 <code>app/components/Hello.module.css</code>：</p>\n<div class=\"language-css codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-css codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token selector class\" style=\"color:hsl(119, 34%, 47%)\">.title</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">color</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#2e8555</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>然后在组件中使用：</p>\n<div class=\"language-tsx codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-tsx codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token imports\">styles</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./Hello.module.css'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">default</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Hello</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">h1</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token tag attr-name\" style=\"color:hsl(35, 99%, 36%)\">className</span><span class=\"token tag script language-javascript script-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">=</span><span class=\"token tag script language-javascript punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token tag script language-javascript\" style=\"color:hsl(5, 74%, 59%)\">styles</span><span class=\"token tag script language-javascript punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token tag script language-javascript property-access\" style=\"color:hsl(5, 74%, 59%)\">title</span><span class=\"token tag script language-javascript punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\">Hello Next.js</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">h1</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"全局样式\">全局样式<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E5%85%A8%E5%B1%80%E6%A0%B7%E5%BC%8F\" class=\"hash-link\" aria-label=\"全局样式的直接链接\" title=\"全局样式的直接链接\">​</a></h3>\n<p>通常在 <code>app/globals.css</code> 引入全站样式，并在根布局 <code>layout.tsx</code> 中导入。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"六数据获取data-fetching\">六、数据获取（Data Fetching）<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E5%85%AD%E6%95%B0%E6%8D%AE%E8%8E%B7%E5%8F%96data-fetching\" class=\"hash-link\" aria-label=\"六、数据获取（Data Fetching）的直接链接\" title=\"六、数据获取（Data Fetching）的直接链接\">​</a></h2>\n<p>在 App Router 下，你常见会遇到几种数据获取方式：</p>\n<ol>\n<li><strong>Server Components 里直接 fetch</strong>（最常见的新手路径）</li>\n<li>使用 <strong>Route Handler</strong> 提供 API，再在客户端请求</li>\n<li>需要更复杂缓存策略时，显式配置 Next.js 的缓存行为</li>\n</ol>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"服务端-fetch-示例\">服务端 fetch 示例<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E6%9C%8D%E5%8A%A1%E7%AB%AF-fetch-%E7%A4%BA%E4%BE%8B\" class=\"hash-link\" aria-label=\"服务端 fetch 示例的直接链接\" title=\"服务端 fetch 示例的直接链接\">​</a></h3>\n<p><code>app/posts/page.tsx</code>：</p>\n<div class=\"language-tsx codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-tsx codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">default</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PostsPage</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> res </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">await</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">fetch</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'https://jsonplaceholder.typicode.com/posts'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 新手先用默认策略即可；需要时再研究缓存/重验证</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    cache</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'no-store'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> posts </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">await</span><span class=\"token plain\"> res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">main</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">      </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">h1</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\">Posts</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">h1</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">      </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">ul</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">posts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">slice</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">5</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">map</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">p</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">any</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token arrow operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">li</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token tag attr-name\" style=\"color:hsl(35, 99%, 36%)\">key</span><span class=\"token tag script language-javascript script-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">=</span><span class=\"token tag script language-javascript punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token tag script language-javascript\" style=\"color:hsl(5, 74%, 59%)\">p</span><span class=\"token tag script language-javascript punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token tag script language-javascript property-access\" style=\"color:hsl(5, 74%, 59%)\">id</span><span class=\"token tag script language-javascript punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">p</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">title</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">li</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">      </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">ul</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">    </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">main</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"七route-handler类似-api-路由\">七、Route Handler（类似 API 路由）<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E4%B8%83route-handler%E7%B1%BB%E4%BC%BC-api-%E8%B7%AF%E7%94%B1\" class=\"hash-link\" aria-label=\"七、Route Handler（类似 API 路由）的直接链接\" title=\"七、Route Handler（类似 API 路由）的直接链接\">​</a></h2>\n<p>在 App Router 中，你可以在 <code>app/api/.../route.ts</code> 里写接口。</p>\n<p>例如 <code>app/api/health/route.ts</code>：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> NextResponse </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'next/server'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token constant\" style=\"color:hsl(35, 99%, 36%)\">GET</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> NextResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> ok</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>访问：<code>/api/health</code></p>\n<p>你也可以扩展为 <code>POST / PUT / DELETE</code> 等方法。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"八构建与部署\">八、构建与部署<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E5%85%AB%E6%9E%84%E5%BB%BA%E4%B8%8E%E9%83%A8%E7%BD%B2\" class=\"hash-link\" aria-label=\"八、构建与部署的直接链接\" title=\"八、构建与部署的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"构建\">构建<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E6%9E%84%E5%BB%BA\" class=\"hash-link\" aria-label=\"构建的直接链接\" title=\"构建的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run build</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"本地预览\">本地预览<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E6%9C%AC%E5%9C%B0%E9%A2%84%E8%A7%88\" class=\"hash-link\" aria-label=\"本地预览的直接链接\" title=\"本地预览的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run start</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"部署到-vercel新手最省事\">部署到 Vercel（新手最省事）<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E9%83%A8%E7%BD%B2%E5%88%B0-vercel%E6%96%B0%E6%89%8B%E6%9C%80%E7%9C%81%E4%BA%8B\" class=\"hash-link\" aria-label=\"部署到 Vercel（新手最省事）的直接链接\" title=\"部署到 Vercel（新手最省事）的直接链接\">​</a></h3>\n<p>Next.js 官方在 Vercel 上体验最佳。一般步骤：</p>\n<ul>\n<li>把项目推到 GitHub</li>\n<li>在 Vercel 创建新项目并导入仓库</li>\n<li>使用 Vercel 默认构建命令（通常就是 <code>npm run build</code>）</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"九常见问题与小结\">九、常见问题与小结<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E4%B9%9D%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98%E4%B8%8E%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"九、常见问题与小结的直接链接\" title=\"九、常见问题与小结的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"常见问题\">常见问题<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98\" class=\"hash-link\" aria-label=\"常见问题的直接链接\" title=\"常见问题的直接链接\">​</a></h3>\n<ul>\n<li>为什么我写的页面路由不生效？<!-- -->\n<ul>\n<li>确认 <code>app</code> 目录下的 <code>page.tsx</code> 是否放对路径（例如 <code>app/about/page.tsx</code> 对应 <code>/about</code>）</li>\n</ul>\n</li>\n<li>为什么数据没有更新？<!-- -->\n<ul>\n<li>App Router 下 <code>fetch</code> 的缓存策略可能不同；新手阶段可先用 <code>cache: 'no-store'</code></li>\n</ul>\n</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"小结\">小结<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"小结的直接链接\" title=\"小结的直接链接\">​</a></h3>\n<ul>\n<li>用 <code>app/</code> 组织路由：<code>layout.tsx</code> + <code>page.tsx</code></li>\n<li>用 <code>Link</code> 做跳转</li>\n<li>用 CSS Modules 管理样式</li>\n<li>在 Server Components 中 <code>fetch</code> 获取数据</li>\n<li>用 <code>app/api/.../route.ts</code> 提供接口</li>\n<li>用 <code>npm run build</code> / <code>npm run start</code> 完成构建与预览</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十学习路径小结\">十、学习路径小结<a href=\"https://xn--qbyt9x.me/blog/nextjs-tutorial#%E5%8D%81%E5%AD%A6%E4%B9%A0%E8%B7%AF%E5%BE%84%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"十、学习路径小结的直接链接\" title=\"十、学习路径小结的直接链接\">​</a></h2>\n<ol>\n<li>新建 Next.js 项目并跑通 <code>npm run dev</code></li>\n<li>写 <code>layout.tsx</code> 和一个 <code>about/page.tsx</code></li>\n<li>用 <code>Link</code> 做页面跳转</li>\n<li>写一个 <code>fetch</code> 示例页面并观察加载行为</li>\n<li>写 <code>app/api/health/route.ts</code> 测试接口</li>\n<li>完成 <code>npm run build</code> 与本地 <code>npm run start</code> 预览</li>\n</ol>\n<p>遇到问题可查阅 <a href=\"https://nextjs.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">Next.js 官方文档</a>。</p>",
            "url": "https://老王.me/blog/nextjs-tutorial",
            "title": "Next.js 完整教程（新手向）",
            "summary": "由浅入深学习 Next.js，覆盖 App Router、路由、数据获取、组件与样式、Route Handler、部署与常见问题等主要知识点。",
            "date_modified": "2026-03-19T15:11:56.000Z",
            "tags": []
        },
        {
            "id": "https://老王.me/blog/nestjs-tutorial",
            "content_html": "<p>本教程面向零基础或刚接触 NestJS 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"一nestjs-简介\">一、NestJS 简介<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E4%B8%80nestjs-%E7%AE%80%E4%BB%8B\" class=\"hash-link\" aria-label=\"一、NestJS 简介的直接链接\" title=\"一、NestJS 简介的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"什么是-nestjs\">什么是 NestJS？<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E4%BB%80%E4%B9%88%E6%98%AF-nestjs\" class=\"hash-link\" aria-label=\"什么是 NestJS？的直接链接\" title=\"什么是 NestJS？的直接链接\">​</a></h3>\n<p>NestJS 是一个基于 <strong>Node.js</strong> 的 <strong>服务端框架</strong>，使用 <strong>TypeScript</strong> 编写，架构风格借鉴了 Angular。特点包括：</p>\n<ul>\n<li><strong>分层清晰</strong>：控制器、服务、模块等概念明确，适合中大型项目</li>\n<li><strong>依赖注入（DI）</strong>：内置 IoC 容器，便于测试与解耦</li>\n<li><strong>TypeScript 优先</strong>：类型安全、装饰器驱动</li>\n<li><strong>可扩展</strong>：支持 REST、GraphQL、WebSocket、微服务等</li>\n<li><strong>生态丰富</strong>：与 TypeORM、Prisma、Passport、class-validator 等无缝集成</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"适合做什么\">适合做什么？<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E9%80%82%E5%90%88%E5%81%9A%E4%BB%80%E4%B9%88\" class=\"hash-link\" aria-label=\"适合做什么？的直接链接\" title=\"适合做什么？的直接链接\">​</a></h3>\n<ul>\n<li>RESTful API / BFF（Backend for Frontend）</li>\n<li>GraphQL 服务</li>\n<li>微服务（配合 Kafka、RabbitMQ 等）</li>\n<li>实时应用（WebSocket、SSE）</li>\n<li>需要严格架构与可维护性的 Node 后端</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"前置知识\">前置知识<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%89%8D%E7%BD%AE%E7%9F%A5%E8%AF%86\" class=\"hash-link\" aria-label=\"前置知识的直接链接\" title=\"前置知识的直接链接\">​</a></h3>\n<ul>\n<li><strong>JavaScript/TypeScript</strong> 基础</li>\n<li><strong>Node.js</strong> 与 npm 基本使用</li>\n<li>了解 <strong>HTTP</strong>、<strong>REST</strong> 概念更佳</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"二环境准备与创建项目\">二、环境准备与创建项目<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E4%BA%8C%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87%E4%B8%8E%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"二、环境准备与创建项目的直接链接\" title=\"二、环境准备与创建项目的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"环境要求\">环境要求<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E7%8E%AF%E5%A2%83%E8%A6%81%E6%B1%82\" class=\"hash-link\" aria-label=\"环境要求的直接链接\" title=\"环境要求的直接链接\">​</a></h3>\n<ul>\n<li><strong>Node.js</strong>：18.x 及以上（建议 20 LTS）</li>\n<li><strong>包管理器</strong>：npm / yarn / pnpm</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"使用-cli-创建项目\">使用 CLI 创建项目<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E4%BD%BF%E7%94%A8-cli-%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"使用 CLI 创建项目的直接链接\" title=\"使用 CLI 创建项目的直接链接\">​</a></h3>\n<p>安装 Nest CLI（可选，也可用 <code>npx</code> 不全局安装）：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> i </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-g</span><span class=\"token plain\"> @nestjs/cli</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">nest new my-app</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>或直接用 npx：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">npx @nestjs/cli new my-app</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>按提示选择包管理器（npm / yarn / pnpm），完成后进入项目并启动：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> my-app</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run start</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>浏览器访问 <strong><a href=\"http://localhost:3000/\" target=\"_blank\" rel=\"noopener noreferrer\">http://localhost:3000</a></strong> 应看到 <code>Hello World!</code>。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"常用脚本\">常用脚本<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%B8%B8%E7%94%A8%E8%84%9A%E6%9C%AC\" class=\"hash-link\" aria-label=\"常用脚本的直接链接\" title=\"常用脚本的直接链接\">​</a></h3>\n<table><thead><tr><th>命令</th><th>说明</th></tr></thead><tbody><tr><td><code>npm run start</code></td><td>开发模式（默认端口 3000）</td></tr><tr><td><code>npm run start:dev</code></td><td>监听文件变化自动重启</td></tr><tr><td><code>npm run start:debug</code></td><td>调试模式</td></tr><tr><td><code>npm run build</code></td><td>编译为 JavaScript 到 <code>dist/</code></td></tr><tr><td><code>npm run start:prod</code></td><td>以生产模式运行 <code>dist/</code></td></tr></tbody></table>\n<div class=\"theme-admonition theme-admonition-tip admonition_fh9h alert alert--success\"><div class=\"admonitionHeading__rZX\"><span class=\"admonitionIcon_krpS\"><svg viewBox=\"0 0 12 16\"><path fill-rule=\"evenodd\" d=\"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z\"></path></svg></span>开发时建议</div><div class=\"admonitionContent_oz3Y\"><p>日常开发用 <code>npm run start:dev</code>，保存即热重载。</p></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"三项目目录结构\">三、项目目录结构<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E4%B8%89%E9%A1%B9%E7%9B%AE%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84\" class=\"hash-link\" aria-label=\"三、项目目录结构的直接链接\" title=\"三、项目目录结构的直接链接\">​</a></h2>\n<div class=\"language-javascript codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-javascript codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">my</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-</span><span class=\"token plain\">app</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── src</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">module</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">ts</span><span class=\"token plain\">      # 根模块</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">controller</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">ts</span><span class=\"token plain\">  # 根控制器</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">service</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">ts</span><span class=\"token plain\">     # 根服务</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   └── main</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">ts</span><span class=\"token plain\">            # 入口文件，引导 </span><span class=\"token maybe-class-name\">Nest</span><span class=\"token plain\"> 应用</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── test</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token plain\">                  # 测试</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── nest</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-</span><span class=\"token plain\">cli</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">json</span><span class=\"token plain\">          # </span><span class=\"token maybe-class-name\">Nest</span><span class=\"token plain\"> </span><span class=\"token constant\" style=\"color:hsl(35, 99%, 36%)\">CLI</span><span class=\"token plain\"> 配置</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── tsconfig</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">json</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">└── </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">json</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<ul>\n<li><strong>main.ts</strong>：创建 <code>NestFactory.create(AppModule)</code>、监听端口、可配置全局管道/前缀等</li>\n<li><strong>app.module.ts</strong>：根模块，通过 <code>imports</code> 聚合其他模块</li>\n<li><strong>app.controller.ts</strong> / <strong>app.service.ts</strong>：根控制器与根服务，演示最基础的请求处理与业务逻辑</li>\n</ul>\n<p>后续会按功能拆成多个模块（如 <code>users</code>、<code>posts</code>），每个模块可有自己的 <code>*.module.ts</code>、<code>*.controller.ts</code>、<code>*.service.ts</code>。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"四核心概念模块控制器服务\">四、核心概念：模块、控制器、服务<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%9B%9B%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5%E6%A8%A1%E5%9D%97%E6%8E%A7%E5%88%B6%E5%99%A8%E6%9C%8D%E5%8A%A1\" class=\"hash-link\" aria-label=\"四、核心概念：模块、控制器、服务的直接链接\" title=\"四、核心概念：模块、控制器、服务的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"41-模块module\">4.1 模块（Module）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#41-%E6%A8%A1%E5%9D%97module\" class=\"hash-link\" aria-label=\"4.1 模块（Module）的直接链接\" title=\"4.1 模块（Module）的直接链接\">​</a></h3>\n<p>模块是组织代码的单元，把<strong>控制器、服务、其他模块</strong>组织在一起。</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// app.module.ts</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> Module </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@nestjs/common'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> AppController </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./app.controller'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> AppService </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./app.service'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Module</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  imports</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 其他模块</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  controllers</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">AppController</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  providers</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">AppService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  exports</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">AppService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 导出后，其他模块可注入 AppService</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">AppModule</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<ul>\n<li><strong>imports</strong>：引入其他模块（使用其 exports）</li>\n<li><strong>controllers</strong>：该模块下的控制器（处理 HTTP 等）</li>\n<li><strong>providers</strong>：该模块下的可注入服务</li>\n<li><strong>exports</strong>：把 providers 暴露给其他模块</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"42-控制器controller\">4.2 控制器（Controller）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#42-%E6%8E%A7%E5%88%B6%E5%99%A8controller\" class=\"hash-link\" aria-label=\"4.2 控制器（Controller）的直接链接\" title=\"4.2 控制器（Controller）的直接链接\">​</a></h3>\n<p>控制器负责<strong>处理入站请求</strong>并返回响应，对应路由与 HTTP 方法。</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// app.controller.ts</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> Controller</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> Get</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> Post</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> Body</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> Param </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@nestjs/common'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> AppService </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./app.service'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Controller</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 路由前缀为空，即根</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">AppController</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">constructor</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">readonly</span><span class=\"token plain\"> appService</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> AppService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Get</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getHello</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">this</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">appService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getHello</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Get</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'info'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getInfo</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'My App'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> version</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'1.0'</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<ul>\n<li><strong>@Controller('prefix')</strong>：该控制器下所有路由共用的前缀，如 <code>@Controller('users')</code> 则路由为 <code>/users/...</code></li>\n<li><strong>@Get()</strong>、<strong>@Post()</strong>、<strong>@Put()</strong>、<strong>@Patch()</strong>、<strong>@Delete()</strong>：对应 HTTP 方法</li>\n<li><strong>constructor</strong> 中注入 <strong>AppService</strong>：由 Nest 的依赖注入提供实例</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"43-服务provider--service\">4.3 服务（Provider / Service）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#43-%E6%9C%8D%E5%8A%A1provider--service\" class=\"hash-link\" aria-label=\"4.3 服务（Provider / Service）的直接链接\" title=\"4.3 服务（Provider / Service）的直接链接\">​</a></h3>\n<p>服务承载<strong>业务逻辑</strong>，被控制器注入并调用，避免在控制器里写复杂逻辑。</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// app.service.ts</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> Injectable </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@nestjs/common'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Injectable</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">AppService</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getHello</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Hello World!'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<ul>\n<li><strong>@Injectable()</strong>：表示该类可由 Nest 的 DI 容器管理，并注入到其他类中</li>\n</ul>\n<p><strong>关系小结</strong>：请求 → 控制器（路由）→ 调用服务（业务）→ 返回响应。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"五依赖注入di\">五、依赖注入（DI）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E4%BA%94%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5di\" class=\"hash-link\" aria-label=\"五、依赖注入（DI）的直接链接\" title=\"五、依赖注入（DI）的直接链接\">​</a></h2>\n<p>Nest 内置 <strong>IoC 容器</strong>：你只声明「需要什么类」，容器负责创建实例并注入。</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Controller</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">AppController</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">constructor</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">readonly</span><span class=\"token plain\"> appService</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> AppService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     ↑ 私有只读    ↑ 类型声明即可，Nest 自动注入实例</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<ul>\n<li><strong>Provider</strong>：在某个模块的 <code>providers</code> 里声明（如 <code>AppService</code>）</li>\n<li><strong>注入</strong>：在控制器或其它服务的 <code>constructor</code> 中写上类型，Nest 会注入该模块或已导入模块的 <code>exports</code> 中的对应实例</li>\n<li><strong>作用域</strong>：默认单例；可按需使用 <code>Scope.REQUEST</code> 等实现请求级实例</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"六路由与请求处理\">六、路由与请求处理<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%85%AD%E8%B7%AF%E7%94%B1%E4%B8%8E%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86\" class=\"hash-link\" aria-label=\"六、路由与请求处理的直接链接\" title=\"六、路由与请求处理的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"61-路径与参数\">6.1 路径与参数<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#61-%E8%B7%AF%E5%BE%84%E4%B8%8E%E5%8F%82%E6%95%B0\" class=\"hash-link\" aria-label=\"6.1 路径与参数的直接链接\" title=\"6.1 路径与参数的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Controller</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'users'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">UsersController</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Get</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\">                      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// GET /users</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findAll</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Get</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">':id'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\">                 </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// GET /users/123</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findOne</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'id'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> id </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Post</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">create</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Body</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> body</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> CreateUserDto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> body</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Put</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">':id'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">update</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'id'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Body</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> body</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> UpdateUserDto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">...</span><span class=\"token plain\">body </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Delete</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">':id'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">remove</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'id'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> deleted</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> id </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>常用参数装饰器：</p>\n<table><thead><tr><th>装饰器</th><th>含义</th></tr></thead><tbody><tr><td><code>@Param('id')</code></td><td>路径参数</td></tr><tr><td><code>@Query('key')</code></td><td>查询参数</td></tr><tr><td><code>@Body()</code></td><td>请求体（JSON）</td></tr><tr><td><code>@Headers('name')</code></td><td>请求头</td></tr><tr><td><code>@Req()</code> / <code>@Res()</code></td><td>原生 request / response（慎用，会失去部分 Nest 能力）</td></tr></tbody></table>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"62-全局路由前缀\">6.2 全局路由前缀<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#62-%E5%85%A8%E5%B1%80%E8%B7%AF%E7%94%B1%E5%89%8D%E7%BC%80\" class=\"hash-link\" aria-label=\"6.2 全局路由前缀的直接链接\" title=\"6.2 全局路由前缀的直接链接\">​</a></h3>\n<p>在 <code>main.ts</code> 中可为所有路由加前缀：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">bootstrap</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> app </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">await</span><span class=\"token plain\"> NestFactory</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">create</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">AppModule</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">setGlobalPrefix</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'api'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 所有路由变为 /api/...</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">await</span><span class=\"token plain\"> app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">listen</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3000</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"七dto-与验证validation\">七、DTO 与验证（Validation）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E4%B8%83dto-%E4%B8%8E%E9%AA%8C%E8%AF%81validation\" class=\"hash-link\" aria-label=\"七、DTO 与验证（Validation）的直接链接\" title=\"七、DTO 与验证（Validation）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"71-为什么用-dto\">7.1 为什么用 DTO<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#71-%E4%B8%BA%E4%BB%80%E4%B9%88%E7%94%A8-dto\" class=\"hash-link\" aria-label=\"7.1 为什么用 DTO的直接链接\" title=\"7.1 为什么用 DTO的直接链接\">​</a></h3>\n<ul>\n<li>定义请求体的<strong>形状</strong>，便于类型提示和文档</li>\n<li>配合 <strong>class-validator</strong> 做<strong>自动校验</strong>，非法请求在进入控制器前被拦截</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"72-安装与启用\">7.2 安装与启用<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#72-%E5%AE%89%E8%A3%85%E4%B8%8E%E5%90%AF%E7%94%A8\" class=\"hash-link\" aria-label=\"7.2 安装与启用的直接链接\" title=\"7.2 安装与启用的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> i class-validator class-transformer</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>在 <code>main.ts</code> 中启用全局验证管道：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> ValidationPipe </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@nestjs/common'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">bootstrap</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> app </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">await</span><span class=\"token plain\"> NestFactory</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">create</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">AppModule</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">useGlobalPipes</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">new</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">ValidationPipe</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    whitelist</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 自动去掉 DTO 中未声明的属性</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    forbidNonWhitelisted</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 若带未声明属性则直接 400</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    transform</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 按类型自动转换（如 string → number）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">await</span><span class=\"token plain\"> app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">listen</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3000</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"73-定义-dto\">7.3 定义 DTO<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#73-%E5%AE%9A%E4%B9%89-dto\" class=\"hash-link\" aria-label=\"7.3 定义 DTO的直接链接\" title=\"7.3 定义 DTO的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// create-user.dto.ts</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> IsString</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> IsEmail</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> MinLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> IsOptional </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'class-validator'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">CreateUserDto</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">IsString</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">MinLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">IsEmail</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  email</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">IsString</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">MinLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">6</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  password</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">IsOptional</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">IsString</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  avatar</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>控制器中直接使用即可，校验失败时 Nest 自动返回 400 与错误信息：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Post</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">create</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Body</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> dto</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> CreateUserDto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">this</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">usersService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">create</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"八管道pipe\">八、管道（Pipe）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%85%AB%E7%AE%A1%E9%81%93pipe\" class=\"hash-link\" aria-label=\"八、管道（Pipe）的直接链接\" title=\"八、管道（Pipe）的直接链接\">​</a></h2>\n<p>管道用于<strong>转换或校验</strong>输入数据，在到达控制器方法之前执行。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"81-内置管道示例\">8.1 内置管道示例<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#81-%E5%86%85%E7%BD%AE%E7%AE%A1%E9%81%93%E7%A4%BA%E4%BE%8B\" class=\"hash-link\" aria-label=\"8.1 内置管道示例的直接链接\" title=\"8.1 内置管道示例的直接链接\">​</a></h3>\n<ul>\n<li><strong>ValidationPipe</strong>：上面已用，配合 class-validator</li>\n<li><strong>ParseIntPipe</strong>：将参数转为整数，否则 400</li>\n</ul>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Get</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">':id'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findOne</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'id'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> ParseIntPipe</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">number</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">this</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">usersService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findOne</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"82-自定义管道\">8.2 自定义管道<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#82-%E8%87%AA%E5%AE%9A%E4%B9%89%E7%AE%A1%E9%81%93\" class=\"hash-link\" aria-label=\"8.2 自定义管道的直接链接\" title=\"8.2 自定义管道的直接链接\">​</a></h3>\n<p>实现 <code>PipeTransform</code> 接口即可：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// parse-bool.pipe.ts</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> PipeTransform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> Injectable</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> BadRequestException </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@nestjs/common'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Injectable</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">ParseBoolPipe</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">implements</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">PipeTransform</span><span class=\"token class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token class-name builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token class-name punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\"> </span><span class=\"token class-name builtin\" style=\"color:hsl(119, 34%, 47%)\">boolean</span><span class=\"token class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">transform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">value</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">boolean</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">value </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">===</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'true'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">value </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">===</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'false'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">new</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">BadRequestException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Expected \"true\" or \"false\"'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>在参数或控制器上使用：<code>@Query('active', ParseBoolPipe) active: boolean</code>。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"九守卫guard\">九、守卫（Guard）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E4%B9%9D%E5%AE%88%E5%8D%ABguard\" class=\"hash-link\" aria-label=\"九、守卫（Guard）的直接链接\" title=\"九、守卫（Guard）的直接链接\">​</a></h2>\n<p>守卫决定<strong>是否允许请求继续</strong>，常用于<strong>权限、角色</strong>校验。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"91-使用方式\">9.1 使用方式<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#91-%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F\" class=\"hash-link\" aria-label=\"9.1 使用方式的直接链接\" title=\"9.1 使用方式的直接链接\">​</a></h3>\n<ul>\n<li>控制器级：<code>@UseGuards(RolesGuard)</code></li>\n<li>方法级：同上</li>\n<li>全局：<code>app.useGlobalGuards(new RolesGuard())</code></li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"92-简单示例\">9.2 简单示例<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#92-%E7%AE%80%E5%8D%95%E7%A4%BA%E4%BE%8B\" class=\"hash-link\" aria-label=\"9.2 简单示例的直接链接\" title=\"9.2 简单示例的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// roles.guard.ts</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> Injectable</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> CanActivate</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> ExecutionContext </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@nestjs/common'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> Reflector </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@nestjs/core'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Injectable</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">RolesGuard</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">implements</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">CanActivate</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">constructor</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> reflector</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Reflector</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">canActivate</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">context</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ExecutionContext</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">boolean</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> requiredRoles </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">this</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">reflector</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token generic-function function\" style=\"color:hsl(221, 87%, 60%)\">get</span><span class=\"token generic-function generic class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token generic-function generic class-name builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token generic-function generic class-name punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token generic-function generic class-name punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token generic-function generic class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'roles'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> context</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getHandler</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!</span><span class=\"token plain\">requiredRoles</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> user </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> context</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">switchToHttp</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> requiredRoles</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">some</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">role</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> user</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?.</span><span class=\"token plain\">roles</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">includes</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">role</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>通过 <strong>Reflector</strong> 读取元数据（如自定义装饰器 <code>@Roles('admin')</code>），再根据 <code>user</code> 判断。若返回 <code>false</code>，Nest 默认返回 403。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十拦截器interceptor\">十、拦截器（Interceptor）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%8D%81%E6%8B%A6%E6%88%AA%E5%99%A8interceptor\" class=\"hash-link\" aria-label=\"十、拦截器（Interceptor）的直接链接\" title=\"十、拦截器（Interceptor）的直接链接\">​</a></h2>\n<p>拦截器可在<strong>请求前/后</strong>统一处理逻辑，如日志、超时、响应格式封装等。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"101-响应映射示例\">10.1 响应映射示例<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#101-%E5%93%8D%E5%BA%94%E6%98%A0%E5%B0%84%E7%A4%BA%E4%BE%8B\" class=\"hash-link\" aria-label=\"10.1 响应映射示例的直接链接\" title=\"10.1 响应映射示例的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// transform.interceptor.ts</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> Injectable</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> NestInterceptor</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> ExecutionContext</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> CallHandler </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@nestjs/common'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> Observable </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'rxjs'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> map </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'rxjs/operators'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">interface</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">Response</span><span class=\"token class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token class-name constant\" style=\"color:hsl(35, 99%, 36%)\">T</span><span class=\"token class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  data</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token constant\" style=\"color:hsl(35, 99%, 36%)\">T</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  timestamp</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Injectable</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">TransformInterceptor</span><span class=\"token class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token class-name constant\" style=\"color:hsl(35, 99%, 36%)\">T</span><span class=\"token class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">implements</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">NestInterceptor</span><span class=\"token class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token class-name constant\" style=\"color:hsl(35, 99%, 36%)\">T</span><span class=\"token class-name punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\"> Response</span><span class=\"token class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token class-name constant\" style=\"color:hsl(35, 99%, 36%)\">T</span><span class=\"token class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">intercept</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">context</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ExecutionContext</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> next</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> CallHandler</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Observable</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Response</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token constant\" style=\"color:hsl(35, 99%, 36%)\">T</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> next</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">handle</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">pipe</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">map</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        timestamp</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">new</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">Date</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">toISOString</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>在 <code>main.ts</code> 中全局注册：<code>app.useGlobalInterceptors(new TransformInterceptor());</code>，则所有控制器返回的数据会被包成 <code>{ data, timestamp }</code>。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"102-典型用途\">10.2 典型用途<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#102-%E5%85%B8%E5%9E%8B%E7%94%A8%E9%80%94\" class=\"hash-link\" aria-label=\"10.2 典型用途的直接链接\" title=\"10.2 典型用途的直接链接\">​</a></h3>\n<ul>\n<li>统一包装 <code>{ code, data, message }</code></li>\n<li>日志、耗时统计</li>\n<li>超时控制（<code>timeout</code> RxJS 操作符）</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十一异常与异常过滤器\">十一、异常与异常过滤器<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%8D%81%E4%B8%80%E5%BC%82%E5%B8%B8%E4%B8%8E%E5%BC%82%E5%B8%B8%E8%BF%87%E6%BB%A4%E5%99%A8\" class=\"hash-link\" aria-label=\"十一、异常与异常过滤器的直接链接\" title=\"十一、异常与异常过滤器的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"111-内置-http-异常\">11.1 内置 HTTP 异常<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#111-%E5%86%85%E7%BD%AE-http-%E5%BC%82%E5%B8%B8\" class=\"hash-link\" aria-label=\"11.1 内置 HTTP 异常的直接链接\" title=\"11.1 内置 HTTP 异常的直接链接\">​</a></h3>\n<p>在服务或控制器中直接抛出，Nest 会转为对应状态码的 JSON：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> NotFoundException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> BadRequestException </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@nestjs/common'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">new</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">NotFoundException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'用户不存在'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">new</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">BadRequestException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'参数错误'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>常用：<code>BadRequestException</code>(400)、<code>UnauthorizedException</code>(401)、<code>ForbiddenException</code>(403)、<code>NotFoundException</code>(404) 等。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"112-异常过滤器exception-filter\">11.2 异常过滤器（Exception Filter）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#112-%E5%BC%82%E5%B8%B8%E8%BF%87%E6%BB%A4%E5%99%A8exception-filter\" class=\"hash-link\" aria-label=\"11.2 异常过滤器（Exception Filter）的直接链接\" title=\"11.2 异常过滤器（Exception Filter）的直接链接\">​</a></h3>\n<p>若希望<strong>统一格式</strong>或对特定异常做特殊处理，可写异常过滤器：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Catch</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">HttpException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">HttpExceptionFilter</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">implements</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">ExceptionFilter</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">catch</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">exception</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> HttpException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> host</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ArgumentsHost</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> ctx </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> host</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">switchToHttp</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> response </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> ctx</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token generic-function function\" style=\"color:hsl(221, 87%, 60%)\">getResponse</span><span class=\"token generic-function generic class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token generic-function generic class-name\" style=\"color:hsl(35, 99%, 36%)\">Response</span><span class=\"token generic-function generic class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> status </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> exception</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getStatus</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> result </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> exception</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    response</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">status</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">status</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      statusCode</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> status</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">typeof</span><span class=\"token plain\"> result </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">===</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'object'</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">result </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">as</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">any</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">message </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> result</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      timestamp</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">new</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">Date</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">toISOString</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>使用：<code>@UseFilters(HttpExceptionFilter)</code> 或 <code>app.useGlobalFilters(new HttpExceptionFilter())</code>。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十二中间件middleware\">十二、中间件（Middleware）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%8D%81%E4%BA%8C%E4%B8%AD%E9%97%B4%E4%BB%B6middleware\" class=\"hash-link\" aria-label=\"十二、中间件（Middleware）的直接链接\" title=\"十二、中间件（Middleware）的直接链接\">​</a></h2>\n<p>中间件在<strong>路由处理器之前</strong>执行，可做日志、解析、限流等。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"121-定义与注册\">12.1 定义与注册<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#121-%E5%AE%9A%E4%B9%89%E4%B8%8E%E6%B3%A8%E5%86%8C\" class=\"hash-link\" aria-label=\"12.1 定义与注册的直接链接\" title=\"12.1 定义与注册的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// logger.middleware.ts</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> Injectable</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> NestMiddleware </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@nestjs/common'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> Request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> Response</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> NextFunction </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'express'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Injectable</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">LoggerMiddleware</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">implements</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">NestMiddleware</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">use</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">req</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> res</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Response</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> next</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> NextFunction</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">console</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">log</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token template-string template-punctuation string\" style=\"color:hsl(119, 34%, 47%)\">`</span><span class=\"token template-string interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">${</span><span class=\"token template-string interpolation\">req</span><span class=\"token template-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token template-string interpolation\">method</span><span class=\"token template-string interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token template-string string\" style=\"color:hsl(119, 34%, 47%)\"> </span><span class=\"token template-string interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">${</span><span class=\"token template-string interpolation\">req</span><span class=\"token template-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token template-string interpolation\">url</span><span class=\"token template-string interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token template-string template-punctuation string\" style=\"color:hsl(119, 34%, 47%)\">`</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">next</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>在模块中挂到指定路由：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">AppModule</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">implements</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">NestModule</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">configure</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">consumer</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> MiddlewareConsumer</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">consumer</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">apply</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">LoggerMiddleware</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">forRoutes</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'*'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"122-函数式中间件\">12.2 函数式中间件<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#122-%E5%87%BD%E6%95%B0%E5%BC%8F%E4%B8%AD%E9%97%B4%E4%BB%B6\" class=\"hash-link\" aria-label=\"12.2 函数式中间件的直接链接\" title=\"12.2 函数式中间件的直接链接\">​</a></h3>\n<p>若无需依赖注入，可写为普通函数，在 <code>consumer.apply(LoggerMiddleware)</code> 处传入即可。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十三配置configmodule\">十三、配置（ConfigModule）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%8D%81%E4%B8%89%E9%85%8D%E7%BD%AEconfigmodule\" class=\"hash-link\" aria-label=\"十三、配置（ConfigModule）的直接链接\" title=\"十三、配置（ConfigModule）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"131-使用-nestjsconfig\">13.1 使用 @nestjs/config<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#131-%E4%BD%BF%E7%94%A8-nestjsconfig\" class=\"hash-link\" aria-label=\"13.1 使用 @nestjs/config的直接链接\" title=\"13.1 使用 @nestjs/config的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> i @nestjs/config</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>根模块中引入：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> ConfigModule </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@nestjs/config'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Module</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  imports</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    ConfigModule</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">forRoot</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      isGlobal</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      envFilePath</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'.env.local'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'.env'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">AppModule</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"132-读取配置\">13.2 读取配置<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#132-%E8%AF%BB%E5%8F%96%E9%85%8D%E7%BD%AE\" class=\"hash-link\" aria-label=\"13.2 读取配置的直接链接\" title=\"13.2 读取配置的直接链接\">​</a></h3>\n<p>在服务或控制器中注入 <code>ConfigService</code>：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">constructor</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> config</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ConfigService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">someMethod</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> port </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">this</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">config</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token generic-function function\" style=\"color:hsl(221, 87%, 60%)\">get</span><span class=\"token generic-function generic class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token generic-function generic class-name builtin\" style=\"color:hsl(119, 34%, 47%)\">number</span><span class=\"token generic-function generic class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'PORT'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3000</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> dbUrl </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">this</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">config</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token generic-function function\" style=\"color:hsl(221, 87%, 60%)\">get</span><span class=\"token generic-function generic class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token generic-function generic class-name builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token generic-function generic class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'DATABASE_URL'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>推荐配合 <code>.env</code> 文件，不要提交敏感信息。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十四数据库typeorm-简介\">十四、数据库（TypeORM 简介）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%8D%81%E5%9B%9B%E6%95%B0%E6%8D%AE%E5%BA%93typeorm-%E7%AE%80%E4%BB%8B\" class=\"hash-link\" aria-label=\"十四、数据库（TypeORM 简介）的直接链接\" title=\"十四、数据库（TypeORM 简介）的直接链接\">​</a></h2>\n<p>Nest 与 <strong>TypeORM</strong>、<strong>Prisma</strong> 等都能很好集成，这里以 TypeORM 为例说明「模块 + 实体」的用法。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"141-安装\">14.1 安装<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#141-%E5%AE%89%E8%A3%85\" class=\"hash-link\" aria-label=\"14.1 安装的直接链接\" title=\"14.1 安装的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> i @nestjs/typeorm typeorm mysql2</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"142-注册与实体\">14.2 注册与实体<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#142-%E6%B3%A8%E5%86%8C%E4%B8%8E%E5%AE%9E%E4%BD%93\" class=\"hash-link\" aria-label=\"14.2 注册与实体的直接链接\" title=\"14.2 注册与实体的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// app.module.ts</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> TypeOrmModule </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@nestjs/typeorm'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> User </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./users/user.entity'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Module</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  imports</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    TypeOrmModule</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">forRoot</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'mysql'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      host</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'localhost'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      port</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3306</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      username</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'root'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      password</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'xxx'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      database</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'mydb'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      entities</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">User</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      synchronize</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 开发时可 true，生产建议 false + 迁移</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    TypeOrmModule</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">forFeature</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">User</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 在 UsersModule 中</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">AppModule</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"143-实体与在服务中注入-repository\">14.3 实体与在服务中注入 Repository<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#143-%E5%AE%9E%E4%BD%93%E4%B8%8E%E5%9C%A8%E6%9C%8D%E5%8A%A1%E4%B8%AD%E6%B3%A8%E5%85%A5-repository\" class=\"hash-link\" aria-label=\"14.3 实体与在服务中注入 Repository的直接链接\" title=\"14.3 实体与在服务中注入 Repository的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// user.entity.ts</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> Entity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> PrimaryGeneratedColumn </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'typeorm'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Entity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'users'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">User</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">PrimaryGeneratedColumn</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">number</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> unique</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  email</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// users.service.ts</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Injectable</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">UsersService</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">constructor</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">InjectRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">User</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> userRepo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Repository</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">User</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">async</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findAll</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">Promise</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">User</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">this</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">userRepo</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">find</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>更多（关系、迁移、事务）请查阅 <a href=\"https://typeorm.io/\" target=\"_blank\" rel=\"noopener noreferrer\">TypeORM 文档</a>。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十五认证jwt-示例\">十五、认证（JWT 示例）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%8D%81%E4%BA%94%E8%AE%A4%E8%AF%81jwt-%E7%A4%BA%E4%BE%8B\" class=\"hash-link\" aria-label=\"十五、认证（JWT 示例）的直接链接\" title=\"十五、认证（JWT 示例）的直接链接\">​</a></h2>\n<p>认证涉及「登录签发 token」和「请求时校验 token」，常用 <strong>Passport + JWT</strong>。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"151-安装\">15.1 安装<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#151-%E5%AE%89%E8%A3%85\" class=\"hash-link\" aria-label=\"15.1 安装的直接链接\" title=\"15.1 安装的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> i @nestjs/passport @nestjs/jwt passport passport-jwt passport-local</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> i </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-D</span><span class=\"token plain\"> @types/passport-jwt @types/passport-local</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"152-思路简述\">15.2 思路简述<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#152-%E6%80%9D%E8%B7%AF%E7%AE%80%E8%BF%B0\" class=\"hash-link\" aria-label=\"15.2 思路简述的直接链接\" title=\"15.2 思路简述的直接链接\">​</a></h3>\n<ul>\n<li><strong>登录</strong>：用 <code>LocalStrategy</code> 校验用户名密码，通过后用 <code>JwtService.sign()</code> 签发 token，返回给前端。</li>\n<li><strong>受保护路由</strong>：用 <code>JwtStrategy</code> 从 Header 的 Bearer token 中解析出用户信息，挂到 <code>request.user</code>；再用 <strong>Guard</strong> 在需要登录的接口上使用 <code>JwtAuthGuard</code>。</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"153-配置与使用\">15.3 配置与使用<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#153-%E9%85%8D%E7%BD%AE%E4%B8%8E%E4%BD%BF%E7%94%A8\" class=\"hash-link\" aria-label=\"15.3 配置与使用的直接链接\" title=\"15.3 配置与使用的直接链接\">​</a></h3>\n<p>在模块中注册：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">JwtModule</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">register</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  secret</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> process</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">env</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token constant\" style=\"color:hsl(35, 99%, 36%)\">JWT_SECRET</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">||</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'your-secret'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  signOptions</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> expiresIn</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'7d'</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">PassportModule</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>在需要登录的控制器或方法上添加：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">UseGuards</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">JwtAuthGuard</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Get</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'profile'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getProfile</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token decorator at operator\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token decorator function\" style=\"color:hsl(221, 87%, 60%)\">Request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> req</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> req</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>具体实现可参考官方文档 <a href=\"https://docs.nestjs.com/security/authentication\" target=\"_blank\" rel=\"noopener noreferrer\">NestJS 认证</a>。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十六测试\">十六、测试<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%8D%81%E5%85%AD%E6%B5%8B%E8%AF%95\" class=\"hash-link\" aria-label=\"十六、测试的直接链接\" title=\"十六、测试的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"161-单元测试服务\">16.1 单元测试（服务）<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#161-%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95%E6%9C%8D%E5%8A%A1\" class=\"hash-link\" aria-label=\"16.1 单元测试（服务）的直接链接\" title=\"16.1 单元测试（服务）的直接链接\">​</a></h3>\n<p>使用 Jest，对服务类进行隔离测试，依赖用 mock：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">describe</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'AppService'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">let</span><span class=\"token plain\"> service</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> AppService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">beforeEach</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">async</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> module </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">await</span><span class=\"token plain\"> Test</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">createTestingModule</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      providers</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">AppService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">compile</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    service </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> module</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token generic-function function\" style=\"color:hsl(221, 87%, 60%)\">get</span><span class=\"token generic-function generic class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token generic-function generic class-name\" style=\"color:hsl(35, 99%, 36%)\">AppService</span><span class=\"token generic-function generic class-name operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">AppService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">it</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'getHello'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">expect</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">service</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getHello</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">toBe</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Hello World!'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"162-e2e-测试\">16.2 E2E 测试<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#162-e2e-%E6%B5%8B%E8%AF%95\" class=\"hash-link\" aria-label=\"16.2 E2E 测试的直接链接\" title=\"16.2 E2E 测试的直接链接\">​</a></h3>\n<p>对完整 HTTP 请求做测试：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">describe</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'AppController (e2e)'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">it</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'/ (GET)'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getHttpServer</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">get</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'/'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">expect</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">200</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">expect</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Hello World!'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>运行：<code>npm run test</code>（单元）、<code>npm run test:e2e</code>（E2E）。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十七构建与部署\">十七、构建与部署<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%8D%81%E4%B8%83%E6%9E%84%E5%BB%BA%E4%B8%8E%E9%83%A8%E7%BD%B2\" class=\"hash-link\" aria-label=\"十七、构建与部署的直接链接\" title=\"十七、构建与部署的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"171-构建\">17.1 构建<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#171-%E6%9E%84%E5%BB%BA\" class=\"hash-link\" aria-label=\"17.1 构建的直接链接\" title=\"17.1 构建的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run build</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>产物在 <code>dist/</code>，为编译后的 JavaScript。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"172-生产运行\">17.2 生产运行<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#172-%E7%94%9F%E4%BA%A7%E8%BF%90%E8%A1%8C\" class=\"hash-link\" aria-label=\"17.2 生产运行的直接链接\" title=\"17.2 生产运行的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run start:prod</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>会执行 <code>node dist/main</code>（或你配置的入口）。生产环境建议用 <strong>PM2</strong>、<strong>Docker</strong> 或云平台的 Node 运行时，并设置好环境变量（如 <code>NODE_ENV=production</code>、数据库与 JWT 的配置）。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"173-部署注意点\">17.3 部署注意点<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#173-%E9%83%A8%E7%BD%B2%E6%B3%A8%E6%84%8F%E7%82%B9\" class=\"hash-link\" aria-label=\"17.3 部署注意点的直接链接\" title=\"17.3 部署注意点的直接链接\">​</a></h3>\n<ul>\n<li>使用 <strong>环境变量</strong> 管理配置，不要写死敏感信息</li>\n<li>数据库用 <strong>迁移</strong> 管理表结构，不要依赖 <code>synchronize: true</code></li>\n<li>可配合 <strong>Nginx</strong> 做反向代理与静态资源</li>\n<li>健康检查可暴露一个 <code>/health</code> 接口供负载均衡使用</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十八学习路径小结\">十八、学习路径小结<a href=\"https://xn--qbyt9x.me/blog/nestjs-tutorial#%E5%8D%81%E5%85%AB%E5%AD%A6%E4%B9%A0%E8%B7%AF%E5%BE%84%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"十八、学习路径小结的直接链接\" title=\"十八、学习路径小结的直接链接\">​</a></h2>\n<ol>\n<li><strong>入门</strong>：创建项目 → 理解 Module / Controller / Service → 改根路由看效果</li>\n<li><strong>请求</strong>：路由、@Param / @Query / @Body、DTO + ValidationPipe</li>\n<li><strong>结构</strong>：按功能拆模块（如 UsersModule）、依赖注入与 exports</li>\n<li><strong>增强</strong>：管道、守卫、拦截器、异常过滤器、中间件</li>\n<li><strong>数据</strong>：ConfigModule、TypeORM/Prisma、实体与 Repository</li>\n<li><strong>安全</strong>：JWT 认证、角色守卫</li>\n<li><strong>质量</strong>：单元测试、E2E 测试</li>\n<li><strong>上线</strong>：build、环境变量、进程管理、健康检查</li>\n</ol>\n<p>遇到问题可查阅 <a href=\"https://docs.nestjs.com/\" target=\"_blank\" rel=\"noopener noreferrer\">NestJS 官方文档</a>。</p>",
            "url": "https://老王.me/blog/nestjs-tutorial",
            "title": "NestJS 完整教程（新手向）",
            "summary": "由浅入深学习 NestJS，覆盖控制器、服务、模块、依赖注入、管道、守卫、拦截器、数据库、认证与部署等主要知识点。",
            "date_modified": "2026-03-19T09:16:45.000Z",
            "tags": []
        },
        {
            "id": "https://老王.me/blog/nodejs-tutorial",
            "content_html": "<p>本教程面向零基础或刚接触 Node.js 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"一nodejs-简介\">一、Node.js 简介<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E4%B8%80nodejs-%E7%AE%80%E4%BB%8B\" class=\"hash-link\" aria-label=\"一、Node.js 简介的直接链接\" title=\"一、Node.js 简介的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"nodejs-是什么\">Node.js 是什么？<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#nodejs-%E6%98%AF%E4%BB%80%E4%B9%88\" class=\"hash-link\" aria-label=\"Node.js 是什么？的直接链接\" title=\"Node.js 是什么？的直接链接\">​</a></h3>\n<p>Node.js 是一个让 JavaScript 在服务器端运行的运行时环境。它解决了浏览器只能运行 JS 的限制，让你可以用 JS 写：</p>\n<ul>\n<li>HTTP 接口服务</li>\n<li>命令行工具</li>\n<li>数据处理脚本</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"node-与浏览器的主要区别\">Node 与浏览器的主要区别<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#node-%E4%B8%8E%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84%E4%B8%BB%E8%A6%81%E5%8C%BA%E5%88%AB\" class=\"hash-link\" aria-label=\"Node 与浏览器的主要区别的直接链接\" title=\"Node 与浏览器的主要区别的直接链接\">​</a></h3>\n<ul>\n<li>API 不一样（浏览器有 DOM，Node 有文件系统/网络等）</li>\n<li>运行模型不同（Node 是服务器侧环境）</li>\n<li>模块系统不同（CommonJS / ESM）</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"二环境准备与-npm\">二、环境准备与 npm<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E4%BA%8C%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87%E4%B8%8E-npm\" class=\"hash-link\" aria-label=\"二、环境准备与 npm的直接链接\" title=\"二、环境准备与 npm的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"安装-nodejs\">安装 Node.js<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E5%AE%89%E8%A3%85-nodejs\" class=\"hash-link\" aria-label=\"安装 Node.js的直接链接\" title=\"安装 Node.js的直接链接\">​</a></h3>\n<ul>\n<li>建议使用 LTS 版本</li>\n<li>可使用 nvm 管理多个版本（可选）</li>\n</ul>\n<p>确认版本：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">node</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"初始化项目\">初始化项目<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E5%88%9D%E5%A7%8B%E5%8C%96%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"初始化项目的直接链接\" title=\"初始化项目的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mkdir</span><span class=\"token plain\"> my-node-app</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> my-node-app</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> init </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-y</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"packagejson-基本字段\">package.json 基本字段<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#packagejson-%E5%9F%BA%E6%9C%AC%E5%AD%97%E6%AE%B5\" class=\"hash-link\" aria-label=\"package.json 基本字段的直接链接\" title=\"package.json 基本字段的直接链接\">​</a></h3>\n<ul>\n<li><code>name</code> / <code>version</code></li>\n<li><code>main</code>（入口）</li>\n<li><code>scripts</code>（一键执行脚本）</li>\n</ul>\n<p>例如加入开发脚本：</p>\n<div class=\"language-json codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-json codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"scripts\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"dev\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"node src/server.js\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"三模块系统commonjs--esm\">三、模块系统（CommonJS / ESM）<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E4%B8%89%E6%A8%A1%E5%9D%97%E7%B3%BB%E7%BB%9Fcommonjs--esm\" class=\"hash-link\" aria-label=\"三、模块系统（CommonJS / ESM）的直接链接\" title=\"三、模块系统（CommonJS / ESM）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"commonjsrequire\">CommonJS：require<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#commonjsrequire\" class=\"hash-link\" aria-label=\"CommonJS：require的直接链接\" title=\"CommonJS：require的直接链接\">​</a></h3>\n<div class=\"language-js codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-js codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// src/math.cjs</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token parameter\">a</span><span class=\"token parameter punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token parameter\"> b</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword control-flow\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> a </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+</span><span class=\"token plain\"> b</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">module</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">exports</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> add </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<div class=\"language-js codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-js codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// src/main.cjs</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> add </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./math.cjs'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token console class-name\" style=\"color:hsl(35, 99%, 36%)\">console</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">log</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"esmimport\">ESM：import<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#esmimport\" class=\"hash-link\" aria-label=\"ESM：import的直接链接\" title=\"ESM：import的直接链接\">​</a></h3>\n<div class=\"language-js codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-js codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// src/math.mjs</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword module\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token parameter\">a</span><span class=\"token parameter punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token parameter\"> b</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword control-flow\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> a </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+</span><span class=\"token plain\"> b</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<div class=\"language-js codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-js codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// src/main.mjs</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword module\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token imports punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token imports\"> add </span><span class=\"token imports punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword module\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./math.mjs'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token console class-name\" style=\"color:hsl(35, 99%, 36%)\">console</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">log</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>建议你在新项目中统一一种模块方式（ESM 更现代），并结合团队约定。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"四异步与事件循环\">四、异步与事件循环<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E5%9B%9B%E5%BC%82%E6%AD%A5%E4%B8%8E%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF\" class=\"hash-link\" aria-label=\"四、异步与事件循环的直接链接\" title=\"四、异步与事件循环的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"promise--async-await\">Promise / async-await<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#promise--async-await\" class=\"hash-link\" aria-label=\"Promise / async-await的直接链接\" title=\"Promise / async-await的直接链接\">​</a></h3>\n<div class=\"language-js codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-js codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">main</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> res </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword control-flow\" style=\"color:hsl(301, 63%, 40%)\">await</span><span class=\"token plain\"> </span><span class=\"token known-class-name class-name\" style=\"color:hsl(35, 99%, 36%)\">Promise</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">resolve</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> </span><span class=\"token literal-property property\" style=\"color:hsl(5, 74%, 59%)\">ok</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token console class-name\" style=\"color:hsl(35, 99%, 36%)\">console</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">log</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">ok</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">main</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"错误处理\">错误处理<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86\" class=\"hash-link\" aria-label=\"错误处理的直接链接\" title=\"错误处理的直接链接\">​</a></h3>\n<div class=\"language-js codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-js codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">run</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword control-flow\" style=\"color:hsl(301, 63%, 40%)\">try</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword control-flow\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">new</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">Error</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'boom'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword control-flow\" style=\"color:hsl(301, 63%, 40%)\">catch</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">e</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token console class-name\" style=\"color:hsl(35, 99%, 36%)\">console</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">error</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'捕获错误：'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> e</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"五http-服务示例原生\">五、HTTP 服务示例（原生）<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E4%BA%94http-%E6%9C%8D%E5%8A%A1%E7%A4%BA%E4%BE%8B%E5%8E%9F%E7%94%9F\" class=\"hash-link\" aria-label=\"五、HTTP 服务示例（原生）的直接链接\" title=\"五、HTTP 服务示例（原生）的直接链接\">​</a></h2>\n<p>创建 <code>src/server.js</code>：</p>\n<div class=\"language-js codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-js codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> http </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'http'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> server </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">createServer</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token parameter\">req</span><span class=\"token parameter punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token parameter\"> res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token arrow operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword control-flow\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">req</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">url</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">===</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'/health'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">setHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Content-Type'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'application/json; charset=utf-8'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">end</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token known-class-name class-name\" style=\"color:hsl(35, 99%, 36%)\">JSON</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">stringify</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> </span><span class=\"token literal-property property\" style=\"color:hsl(5, 74%, 59%)\">ok</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword control-flow\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">statusCode</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">404</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">end</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Not Found'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">server</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">listen</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3000</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token arrow operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token console class-name\" style=\"color:hsl(35, 99%, 36%)\">console</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">log</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'server running at http://localhost:3000'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>启动：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">node</span><span class=\"token plain\"> src/server.js</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>访问：<code>http://localhost:3000/health</code></p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"六使用-express-构建-api\">六、使用 Express 构建 API<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E5%85%AD%E4%BD%BF%E7%94%A8-express-%E6%9E%84%E5%BB%BA-api\" class=\"hash-link\" aria-label=\"六、使用 Express 构建 API的直接链接\" title=\"六、使用 Express 构建 API的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"安装\">安装<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E5%AE%89%E8%A3%85\" class=\"hash-link\" aria-label=\"安装的直接链接\" title=\"安装的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> i express</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"简单路由\">简单路由<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E7%AE%80%E5%8D%95%E8%B7%AF%E7%94%B1\" class=\"hash-link\" aria-label=\"简单路由的直接链接\" title=\"简单路由的直接链接\">​</a></h3>\n<p>创建 <code>src/app.js</code>：</p>\n<div class=\"language-js codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-js codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> express </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'express'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> app </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">express</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">use</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">express</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">get</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'/health'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token parameter\">_req</span><span class=\"token parameter punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token parameter\"> res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token arrow operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> </span><span class=\"token literal-property property\" style=\"color:hsl(5, 74%, 59%)\">ok</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">post</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'/echo'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token parameter\">req</span><span class=\"token parameter punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token parameter\"> res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token arrow operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> </span><span class=\"token literal-property property\" style=\"color:hsl(5, 74%, 59%)\">received</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> req</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">body</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">listen</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3000</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token arrow operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token console class-name\" style=\"color:hsl(35, 99%, 36%)\">console</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">log</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'express running at http://localhost:3000'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>启动：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">node</span><span class=\"token plain\"> src/app.js</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"七数据访问入门思路\">七、数据访问（入门思路）<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E4%B8%83%E6%95%B0%E6%8D%AE%E8%AE%BF%E9%97%AE%E5%85%A5%E9%97%A8%E6%80%9D%E8%B7%AF\" class=\"hash-link\" aria-label=\"七、数据访问（入门思路）的直接链接\" title=\"七、数据访问（入门思路）的直接链接\">​</a></h2>\n<p>新手建议先把“接口层”和“数据层”分开。你可以从简单存储开始，例如：</p>\n<ul>\n<li>内存对象（原型期）</li>\n<li>JSON 文件（演示用）</li>\n</ul>\n<p>等接口逻辑稳定后再替换为数据库（如 PostgreSQL / MySQL）。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"八日志与错误处理\">八、日志与错误处理<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E5%85%AB%E6%97%A5%E5%BF%97%E4%B8%8E%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86\" class=\"hash-link\" aria-label=\"八、日志与错误处理的直接链接\" title=\"八、日志与错误处理的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"统一错误返回\">统一错误返回<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E7%BB%9F%E4%B8%80%E9%94%99%E8%AF%AF%E8%BF%94%E5%9B%9E\" class=\"hash-link\" aria-label=\"统一错误返回的直接链接\" title=\"统一错误返回的直接链接\">​</a></h3>\n<p>Express 可以通过中间件做统一处理：</p>\n<div class=\"language-js codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-js codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">use</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token parameter\">err</span><span class=\"token parameter punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token parameter\"> _req</span><span class=\"token parameter punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token parameter\"> res</span><span class=\"token parameter punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token parameter\"> _next</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token arrow operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token console class-name\" style=\"color:hsl(35, 99%, 36%)\">console</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">error</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">err</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  res</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">status</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">500</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> </span><span class=\"token literal-property property\" style=\"color:hsl(5, 74%, 59%)\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'internal error'</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"日志建议\">日志建议<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E6%97%A5%E5%BF%97%E5%BB%BA%E8%AE%AE\" class=\"hash-link\" aria-label=\"日志建议的直接链接\" title=\"日志建议的直接链接\">​</a></h3>\n<ul>\n<li>开发期：<code>console.log</code> 够用</li>\n<li>生产期：用成熟日志库（如 pino/winston）更可观测</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"九测试与调试\">九、测试与调试<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E4%B9%9D%E6%B5%8B%E8%AF%95%E4%B8%8E%E8%B0%83%E8%AF%95\" class=\"hash-link\" aria-label=\"九、测试与调试的直接链接\" title=\"九、测试与调试的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"jest-示例单元测试\">Jest 示例（单元测试）<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#jest-%E7%A4%BA%E4%BE%8B%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95\" class=\"hash-link\" aria-label=\"Jest 示例（单元测试）的直接链接\" title=\"Jest 示例（单元测试）的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> i </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-D</span><span class=\"token plain\"> jest</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>在 <code>package.json</code> 添加：</p>\n<div class=\"language-json codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-json codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"scripts\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"test\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"jest\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>写测试：</p>\n<div class=\"language-js codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-js codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token parameter\">a</span><span class=\"token parameter punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token parameter\"> b</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword control-flow\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> a </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+</span><span class=\"token plain\"> b</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">test</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'add'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token arrow operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">expect</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token method function property-access\" style=\"color:hsl(221, 87%, 60%)\">toBe</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"调试\">调试<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E8%B0%83%E8%AF%95\" class=\"hash-link\" aria-label=\"调试的直接链接\" title=\"调试的直接链接\">​</a></h3>\n<ul>\n<li>使用断点调试（IDE）</li>\n<li>关键函数先写日志，再逐步定位问题</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十部署与小结\">十、部署与小结<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E5%8D%81%E9%83%A8%E7%BD%B2%E4%B8%8E%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"十、部署与小结的直接链接\" title=\"十、部署与小结的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"部署常见方式\">部署常见方式<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E9%83%A8%E7%BD%B2%E5%B8%B8%E8%A7%81%E6%96%B9%E5%BC%8F\" class=\"hash-link\" aria-label=\"部署常见方式的直接链接\" title=\"部署常见方式的直接链接\">​</a></h3>\n<ul>\n<li>静态站点不适用后端部署</li>\n<li>后端服务通常使用：<!-- -->\n<ul>\n<li>进程管理：PM2</li>\n<li>容器：Docker</li>\n<li>平台：Vercel/Render/Fly.io 等（取决于你的项目形态）</li>\n</ul>\n</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"小结\">小结<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"小结的直接链接\" title=\"小结的直接链接\">​</a></h3>\n<ul>\n<li>Node：用 JS 写后端服务</li>\n<li>npm：管理依赖与脚本</li>\n<li>模块：CommonJS / ESM 二选一并统一</li>\n<li>异步：Promise 与 async/await</li>\n<li>API：原生 http 与 Express 入门</li>\n<li>质量：Jest 测试与统一错误处理</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十一学习路径小结\">十一、学习路径小结<a href=\"https://xn--qbyt9x.me/blog/nodejs-tutorial#%E5%8D%81%E4%B8%80%E5%AD%A6%E4%B9%A0%E8%B7%AF%E5%BE%84%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"十一、学习路径小结的直接链接\" title=\"十一、学习路径小结的直接链接\">​</a></h2>\n<ol>\n<li>安装 Node 并完成 npm 项目初始化</li>\n<li>理解模块系统（require/import）</li>\n<li>写几个 async/await 的函数并练习错误捕获</li>\n<li>用原生 http 实现 <code>/health</code></li>\n<li>用 Express 做一个最小 API（health + echo）</li>\n<li>加上至少 1-2 个 Jest 单测，再考虑部署</li>\n</ol>\n<p>遇到问题可查阅 <a href=\"https://nodejs.org/en/docs/\" target=\"_blank\" rel=\"noopener noreferrer\">Node.js 官方文档</a> 与社区示例。</p>",
            "url": "https://老王.me/blog/nodejs-tutorial",
            "title": "Node.js 完整教程（新手向）",
            "summary": "由浅入深学习 Node.js，覆盖环境与 npm、模块系统、异步与事件循环、HTTP 与 Express、日志错误处理、测试与部署等主要知识点。",
            "date_modified": "2026-03-19T15:11:56.000Z",
            "tags": []
        },
        {
            "id": "https://老王.me/blog/python-tutorial",
            "content_html": "<p>本教程面向零基础或刚接触 Python 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"一python-简介\">一、Python 简介<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E4%B8%80python-%E7%AE%80%E4%BB%8B\" class=\"hash-link\" aria-label=\"一、Python 简介的直接链接\" title=\"一、Python 简介的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"什么是-python\">什么是 Python？<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E4%BB%80%E4%B9%88%E6%98%AF-python\" class=\"hash-link\" aria-label=\"什么是 Python？的直接链接\" title=\"什么是 Python？的直接链接\">​</a></h3>\n<p>Python 是一种 <strong>解释型</strong>、<strong>面向对象</strong>且以 <strong>可读性强</strong> 著称的编程语言。它的生态非常成熟，常见用途包括：</p>\n<ul>\n<li>脚本自动化（写小工具、处理文件、跑任务）</li>\n<li>数据分析与数据工程（Pandas、NumPy 等）</li>\n<li>Web 后端与接口服务（FastAPI、Flask 等）</li>\n<li>AI / 机器学习（生态强，社区资源多）</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"适合做什么\">适合做什么？<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E9%80%82%E5%90%88%E5%81%9A%E4%BB%80%E4%B9%88\" class=\"hash-link\" aria-label=\"适合做什么？的直接链接\" title=\"适合做什么？的直接链接\">​</a></h3>\n<ul>\n<li>想用更少代码快速完成一个功能</li>\n<li>想做 API、脚本、爬虫或数据处理</li>\n<li>希望语言本身对新手友好，并且拥有大量开源库</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"二环境准备与运行方式\">二、环境准备与运行方式<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E4%BA%8C%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87%E4%B8%8E%E8%BF%90%E8%A1%8C%E6%96%B9%E5%BC%8F\" class=\"hash-link\" aria-label=\"二、环境准备与运行方式的直接链接\" title=\"二、环境准备与运行方式的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"安装-python\">安装 Python<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%AE%89%E8%A3%85-python\" class=\"hash-link\" aria-label=\"安装 Python的直接链接\" title=\"安装 Python的直接链接\">​</a></h3>\n<ul>\n<li>到官方站下载安装包（推荐 3.x 最新稳定版）</li>\n<li>如果你在 Linux/WSL 下，也可以使用系统包管理器或版本管理工具（如 pyenv）</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"创建虚拟环境强烈建议\">创建虚拟环境（强烈建议）<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%88%9B%E5%BB%BA%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83%E5%BC%BA%E7%83%88%E5%BB%BA%E8%AE%AE\" class=\"hash-link\" aria-label=\"创建虚拟环境（强烈建议）的直接链接\" title=\"创建虚拟环境（强烈建议）的直接链接\">​</a></h3>\n<p>避免把依赖装到全局 Python，造成版本冲突：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">python </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-m</span><span class=\"token plain\"> venv .venv</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>激活虚拟环境：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># macOS / Linux</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">source</span><span class=\"token plain\"> .venv/bin/activate</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># Windows（PowerShell）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">\\</span><span class=\"token plain\">.venv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">\\</span><span class=\"token plain\">Scripts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">\\</span><span class=\"token plain\">Activate.ps1</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>升级 pip 并安装依赖：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">python </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-m</span><span class=\"token plain\"> pip </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-U</span><span class=\"token plain\"> pip</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<blockquote>\n<p>提示：创建虚拟环境可以让每个项目的依赖互相独立，更容易复现和部署。</p>\n</blockquote>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"运行脚本\">运行脚本<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E8%BF%90%E8%A1%8C%E8%84%9A%E6%9C%AC\" class=\"hash-link\" aria-label=\"运行脚本的直接链接\" title=\"运行脚本的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">python main.py</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>也可以直接用模块方式运行：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">python </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-m</span><span class=\"token plain\"> pip </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--version</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"三基本语法与数据类型\">三、基本语法与数据类型<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E4%B8%89%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95%E4%B8%8E%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B\" class=\"hash-link\" aria-label=\"三、基本语法与数据类型的直接链接\" title=\"三、基本语法与数据类型的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"变量与常量\">变量与常量<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%8F%98%E9%87%8F%E4%B8%8E%E5%B8%B8%E9%87%8F\" class=\"hash-link\" aria-label=\"变量与常量的直接链接\" title=\"变量与常量的直接链接\">​</a></h3>\n<p>Python 不需要写类型声明：</p>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Alice\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">age </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">18</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">is_student </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">True</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"常用数据类型\">常用数据类型<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%B8%B8%E7%94%A8%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B\" class=\"hash-link\" aria-label=\"常用数据类型的直接链接\" title=\"常用数据类型的直接链接\">​</a></h3>\n<ul>\n<li><code>int</code>：整数</li>\n<li><code>float</code>：浮点数</li>\n<li><code>str</code>：字符串</li>\n<li><code>bool</code>：布尔值</li>\n<li><code>list</code>：列表（可变）</li>\n<li><code>tuple</code>：元组（不可变，推荐当作“固定结构”使用）</li>\n<li><code>dict</code>：字典（键值对）</li>\n<li><code>set</code>：集合（去重）</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"字符串拼接f-string\">字符串拼接：f-string<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%8B%BC%E6%8E%A5f-string\" class=\"hash-link\" aria-label=\"字符串拼接：f-string的直接链接\" title=\"字符串拼接：f-string的直接链接\">​</a></h3>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">user </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Bob\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">score </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">95.5</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">print</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-interpolation string\" style=\"color:hsl(119, 34%, 47%)\">f\"</span><span class=\"token string-interpolation interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token string-interpolation interpolation\">user</span><span class=\"token string-interpolation interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token string-interpolation string\" style=\"color:hsl(119, 34%, 47%)\"> 的得分是 </span><span class=\"token string-interpolation interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token string-interpolation interpolation\">score</span><span class=\"token string-interpolation interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token string-interpolation string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"四条件与循环\">四、条件与循环<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%9B%9B%E6%9D%A1%E4%BB%B6%E4%B8%8E%E5%BE%AA%E7%8E%AF\" class=\"hash-link\" aria-label=\"四、条件与循环的直接链接\" title=\"四、条件与循环的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"条件分支\">条件分支<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E6%9D%A1%E4%BB%B6%E5%88%86%E6%94%AF\" class=\"hash-link\" aria-label=\"条件分支的直接链接\" title=\"条件分支的直接链接\">​</a></h3>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">age </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">20</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> age </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">18</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">print</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"adult\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">print</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"teen\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"循环\">循环<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%BE%AA%E7%8E%AF\" class=\"hash-link\" aria-label=\"循环的直接链接\" title=\"循环的直接链接\">​</a></h3>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">for</span><span class=\"token plain\"> i </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">in</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">range</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">5</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">print</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">i</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">items </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"a\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"b\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"c\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">for</span><span class=\"token plain\"> item </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">in</span><span class=\"token plain\"> items</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">print</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">item</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>while 循环：</p>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">count </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">while</span><span class=\"token plain\"> count </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    count </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">print</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">count</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"五函数与模块\">五、函数与模块<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E4%BA%94%E5%87%BD%E6%95%B0%E4%B8%8E%E6%A8%A1%E5%9D%97\" class=\"hash-link\" aria-label=\"五、函数与模块的直接链接\" title=\"五、函数与模块的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"函数定义与返回值\">函数定义与返回值<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%87%BD%E6%95%B0%E5%AE%9A%E4%B9%89%E4%B8%8E%E8%BF%94%E5%9B%9E%E5%80%BC\" class=\"hash-link\" aria-label=\"函数定义与返回值的直接链接\" title=\"函数定义与返回值的直接链接\">​</a></h3>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">def</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">a</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> b</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> a </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+</span><span class=\"token plain\"> b</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>其中：</p>\n<ul>\n<li><code>a: int</code> / <code>b: int</code> 是类型标注（运行时不强制）</li>\n<li><code>-&gt; int</code> 表示返回类型</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"模块与导入\">模块与导入<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E6%A8%A1%E5%9D%97%E4%B8%8E%E5%AF%BC%E5%85%A5\" class=\"hash-link\" aria-label=\"模块与导入的直接链接\" title=\"模块与导入的直接链接\">​</a></h3>\n<p>假设有 <code>utils.py</code>：</p>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># utils.py</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">def</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">hello</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">str</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">str</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token string-interpolation string\" style=\"color:hsl(119, 34%, 47%)\">f\"hello, </span><span class=\"token string-interpolation interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token string-interpolation interpolation\">name</span><span class=\"token string-interpolation interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token string-interpolation string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>在 <code>main.py</code>：</p>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> utils </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> hello</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">print</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">hello</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"world\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"六面向对象与异常处理\">六、面向对象与异常处理<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%85%AD%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E4%B8%8E%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86\" class=\"hash-link\" aria-label=\"六、面向对象与异常处理的直接链接\" title=\"六、面向对象与异常处理的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"类与对象\">类与对象<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E7%B1%BB%E4%B8%8E%E5%AF%B9%E8%B1%A1\" class=\"hash-link\" aria-label=\"类与对象的直接链接\" title=\"类与对象的直接链接\">​</a></h3>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">User</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">def</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">__init__</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">self</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">str</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        self</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> name</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">def</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">greet</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">self</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">str</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token string-interpolation string\" style=\"color:hsl(119, 34%, 47%)\">f\"hi, </span><span class=\"token string-interpolation interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token string-interpolation interpolation\">self</span><span class=\"token string-interpolation interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token string-interpolation interpolation\">name</span><span class=\"token string-interpolation interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token string-interpolation string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">u </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> User</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Tom\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">print</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">u</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">greet</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"异常try--except\">异常（try / except）<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%BC%82%E5%B8%B8try--except\" class=\"hash-link\" aria-label=\"异常（try / except）的直接链接\" title=\"异常（try / except）的直接链接\">​</a></h3>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">try</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    n </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"123\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">except</span><span class=\"token plain\"> ValueError </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">as</span><span class=\"token plain\"> e</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">print</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"转换失败：\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> e</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>也可以在捕获后重新抛出：</p>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">try</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    n </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"abc\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">except</span><span class=\"token plain\"> ValueError </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">as</span><span class=\"token plain\"> e</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">raise</span><span class=\"token plain\"> RuntimeError</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"输入不是数字\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> e</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"七文件与数据格式\">七、文件与数据格式<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E4%B8%83%E6%96%87%E4%BB%B6%E4%B8%8E%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F\" class=\"hash-link\" aria-label=\"七、文件与数据格式的直接链接\" title=\"七、文件与数据格式的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"读写文件\">读写文件<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E8%AF%BB%E5%86%99%E6%96%87%E4%BB%B6\" class=\"hash-link\" aria-label=\"读写文件的直接链接\" title=\"读写文件的直接链接\">​</a></h3>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">with</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">open</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"data.txt\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"w\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> encoding</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"utf-8\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">as</span><span class=\"token plain\"> f</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    f</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">write</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Hello\\n\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">with</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">open</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"data.txt\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"r\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> encoding</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"utf-8\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">as</span><span class=\"token plain\"> f</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    content </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> f</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">read</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">print</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">content</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"json\">JSON<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#json\" class=\"hash-link\" aria-label=\"JSON的直接链接\" title=\"JSON的直接链接\">​</a></h3>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> json</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">obj </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"name\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Alice\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"age\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">18</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">with</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">open</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"data.json\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"w\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> encoding</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"utf-8\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">as</span><span class=\"token plain\"> f</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dump</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">obj</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> f</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> ensure_ascii</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">False</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> indent</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">with</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">open</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"data.json\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"r\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> encoding</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"utf-8\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">as</span><span class=\"token plain\"> f</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    data </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">load</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">f</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">print</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"name\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"八类型标注与项目结构\">八、类型标注与项目结构<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%85%AB%E7%B1%BB%E5%9E%8B%E6%A0%87%E6%B3%A8%E4%B8%8E%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84\" class=\"hash-link\" aria-label=\"八、类型标注与项目结构的直接链接\" title=\"八、类型标注与项目结构的直接链接\">​</a></h2>\n<p>当项目变大时，类型标注可以提升可维护性。一个常见结构：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">my-project/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── src/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   └── app/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│       ├── main.py</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│       └── services/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── tests/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── pyproject.toml  (或 requirements.txt)</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">└── README.md</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>类型检查工具常见包括 <code>mypy</code>（可按需启用）。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"九第三方库与包管理\">九、第三方库与包管理<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E4%B9%9D%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%93%E4%B8%8E%E5%8C%85%E7%AE%A1%E7%90%86\" class=\"hash-link\" aria-label=\"九、第三方库与包管理的直接链接\" title=\"九、第三方库与包管理的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"requirementstxt\">requirements.txt<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#requirementstxt\" class=\"hash-link\" aria-label=\"requirements.txt的直接链接\" title=\"requirements.txt的直接链接\">​</a></h3>\n<p>安装依赖：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">pip </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> requests</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>生成依赖清单：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">pip freeze </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> requirements.txt</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>在新环境安装：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">pip </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-r</span><span class=\"token plain\"> requirements.txt</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"常用库举例\">常用库举例<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%B8%B8%E7%94%A8%E5%BA%93%E4%B8%BE%E4%BE%8B\" class=\"hash-link\" aria-label=\"常用库举例的直接链接\" title=\"常用库举例的直接链接\">​</a></h3>\n<ul>\n<li><code>requests</code>：发 HTTP 请求</li>\n<li><code>pydantic</code>：数据校验与结构化（FastAPI 经常用）</li>\n<li><code>httpx</code>：现代 HTTP 客户端（异步友好）</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十web-入门fastapi\">十、Web 入门（FastAPI）<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%8D%81web-%E5%85%A5%E9%97%A8fastapi\" class=\"hash-link\" aria-label=\"十、Web 入门（FastAPI）的直接链接\" title=\"十、Web 入门（FastAPI）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"安装\">安装<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%AE%89%E8%A3%85\" class=\"hash-link\" aria-label=\"安装的直接链接\" title=\"安装的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">pip </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> fastapi uvicorn</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"最小服务\">最小服务<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E6%9C%80%E5%B0%8F%E6%9C%8D%E5%8A%A1\" class=\"hash-link\" aria-label=\"最小服务的直接链接\" title=\"最小服务的直接链接\">​</a></h3>\n<p>创建 <code>main.py</code>：</p>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> fastapi </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> FastAPI</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">app </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> FastAPI</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token decorator annotation punctuation\" style=\"color:hsl(119, 34%, 47%)\">@app</span><span class=\"token decorator annotation punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token decorator annotation punctuation\" style=\"color:hsl(119, 34%, 47%)\">get</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"/health\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">def</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">health</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"ok\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">True</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>启动服务：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">uvicorn main:app </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--reload</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--port</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">8000</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>访问：<code>http://localhost:8000/health</code></p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十一测试与调试\">十一、测试与调试<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%8D%81%E4%B8%80%E6%B5%8B%E8%AF%95%E4%B8%8E%E8%B0%83%E8%AF%95\" class=\"hash-link\" aria-label=\"十一、测试与调试的直接链接\" title=\"十一、测试与调试的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"安装-pytest\">安装 pytest<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%AE%89%E8%A3%85-pytest\" class=\"hash-link\" aria-label=\"安装 pytest的直接链接\" title=\"安装 pytest的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">pip </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-U</span><span class=\"token plain\"> pytest</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>写测试示例：<code>tests/test_main.py</code></p>\n<div class=\"language-python codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-python codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">def</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">test_add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">assert</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">==</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>运行：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">pytest</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"调试小技巧\">调试小技巧<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E8%B0%83%E8%AF%95%E5%B0%8F%E6%8A%80%E5%B7%A7\" class=\"hash-link\" aria-label=\"调试小技巧的直接链接\" title=\"调试小技巧的直接链接\">​</a></h3>\n<ul>\n<li>使用 <code>print()</code> 快速定位问题</li>\n<li>必要时使用 <code>logging</code> 代替 <code>print</code>（更可控）</li>\n<li>Python 可直接用 <code>breakpoint()</code> 进入调试</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十二部署与小结\">十二、部署与小结<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%8D%81%E4%BA%8C%E9%83%A8%E7%BD%B2%E4%B8%8E%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"十二、部署与小结的直接链接\" title=\"十二、部署与小结的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"部署思路\">部署思路<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E9%83%A8%E7%BD%B2%E6%80%9D%E8%B7%AF\" class=\"hash-link\" aria-label=\"部署思路的直接链接\" title=\"部署思路的直接链接\">​</a></h3>\n<ul>\n<li>使用虚拟环境或容器打包依赖</li>\n<li>保证环境变量（如数据库连接串）在部署平台配置</li>\n<li>生产环境通常用 <code>uvicorn</code> + 反向代理（如 Nginx）</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"小结\">小结<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"小结的直接链接\" title=\"小结的直接链接\">​</a></h3>\n<ul>\n<li>Python 基础：语法、数据类型、控制流</li>\n<li>工程能力：虚拟环境、requirements、项目结构</li>\n<li>Web：FastAPI + uvicorn 快速起服务</li>\n<li>质量：pytest 做测试</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十三学习路径小结\">十三、学习路径小结<a href=\"https://xn--qbyt9x.me/blog/python-tutorial#%E5%8D%81%E4%B8%89%E5%AD%A6%E4%B9%A0%E8%B7%AF%E5%BE%84%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"十三、学习路径小结的直接链接\" title=\"十三、学习路径小结的直接链接\">​</a></h2>\n<ol>\n<li>学会变量、函数、循环与常见数据结构</li>\n<li>逐步引入类型标注，让代码更易维护</li>\n<li>熟悉虚拟环境与依赖管理（requirements）</li>\n<li>做一个简单 Web 服务（FastAPI）</li>\n<li>写至少几条测试（pytest），再逐步扩展项目</li>\n</ol>\n<p>遇到问题可查阅 <a href=\"https://docs.python.org/zh-cn/\" target=\"_blank\" rel=\"noopener noreferrer\">Python 官方文档</a> 与社区示例。</p>",
            "url": "https://老王.me/blog/python-tutorial",
            "title": "Python 完整教程（新手向）",
            "summary": "由浅入深学习 Python，覆盖语法基础、类型标注、异常处理、第三方库、Web 入门、测试、调试与部署等主要知识点。",
            "date_modified": "2026-03-19T15:11:56.000Z",
            "tags": []
        },
        {
            "id": "https://老王.me/blog/go-tutorial",
            "content_html": "<p>本教程面向零基础或刚接触 Go 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"一go-简介\">一、Go 简介<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E4%B8%80go-%E7%AE%80%E4%BB%8B\" class=\"hash-link\" aria-label=\"一、Go 简介的直接链接\" title=\"一、Go 简介的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"go-是什么\">Go 是什么？<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#go-%E6%98%AF%E4%BB%80%E4%B9%88\" class=\"hash-link\" aria-label=\"Go 是什么？的直接链接\" title=\"Go 是什么？的直接链接\">​</a></h3>\n<p>Go（又称 Golang）是一种由 Google 主导开发的编程语言，特点包括：</p>\n<ul>\n<li>语法简洁，学习成本相对低</li>\n<li>并发模型原生支持（goroutine + channel）</li>\n<li>编译为本地二进制，部署方便</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"适合做什么\">适合做什么？<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E9%80%82%E5%90%88%E5%81%9A%E4%BB%80%E4%B9%88\" class=\"hash-link\" aria-label=\"适合做什么？的直接链接\" title=\"适合做什么？的直接链接\">​</a></h3>\n<ul>\n<li>高性能网络服务（HTTP/RPC）</li>\n<li>需要并发处理的场景</li>\n<li>云原生、工具类程序</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"二安装与工作区\">二、安装与工作区<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E4%BA%8C%E5%AE%89%E8%A3%85%E4%B8%8E%E5%B7%A5%E4%BD%9C%E5%8C%BA\" class=\"hash-link\" aria-label=\"二、安装与工作区的直接链接\" title=\"二、安装与工作区的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"安装-go\">安装 Go<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E5%AE%89%E8%A3%85-go\" class=\"hash-link\" aria-label=\"安装 Go的直接链接\" title=\"安装 Go的直接链接\">​</a></h3>\n<ul>\n<li>建议安装最新稳定版</li>\n<li>确认版本：</li>\n</ul>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">go version</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"创建模块go-modules\">创建模块（Go Modules）<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E5%88%9B%E5%BB%BA%E6%A8%A1%E5%9D%97go-modules\" class=\"hash-link\" aria-label=\"创建模块（Go Modules）的直接链接\" title=\"创建模块（Go Modules）的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mkdir</span><span class=\"token plain\"> my-go-app</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> my-go-app</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">go mod init example.com/my-go-app</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Go 的依赖管理通常基于 <code>go.mod</code>。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"三基础语法\">三、基础语法<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E4%B8%89%E5%9F%BA%E7%A1%80%E8%AF%AD%E6%B3%95\" class=\"hash-link\" aria-label=\"三、基础语法的直接链接\" title=\"三、基础语法的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"最小可运行程序\">最小可运行程序<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E6%9C%80%E5%B0%8F%E5%8F%AF%E8%BF%90%E8%A1%8C%E7%A8%8B%E5%BA%8F\" class=\"hash-link\" aria-label=\"最小可运行程序的直接链接\" title=\"最小可运行程序的直接链接\">​</a></h3>\n<p>创建 <code>main.go</code>：</p>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> main</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"fmt\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">func</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">main</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\tfmt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Println</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Hello, Go!\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"变量与常量\">变量与常量<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E5%8F%98%E9%87%8F%E4%B8%8E%E5%B8%B8%E9%87%8F\" class=\"hash-link\" aria-label=\"变量与常量的直接链接\" title=\"变量与常量的直接链接\">​</a></h3>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Alice\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> age </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">18</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> appName </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"my-app\"</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"常用类型\">常用类型<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E5%B8%B8%E7%94%A8%E7%B1%BB%E5%9E%8B\" class=\"hash-link\" aria-label=\"常用类型的直接链接\" title=\"常用类型的直接链接\">​</a></h3>\n<ul>\n<li><code>int</code> / <code>int64</code></li>\n<li><code>string</code></li>\n<li><code>bool</code></li>\n<li><code>float64</code></li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"四函数包与模块\">四、函数、包与模块<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E5%9B%9B%E5%87%BD%E6%95%B0%E5%8C%85%E4%B8%8E%E6%A8%A1%E5%9D%97\" class=\"hash-link\" aria-label=\"四、函数、包与模块的直接链接\" title=\"四、函数、包与模块的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"函数\">函数<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E5%87%BD%E6%95%B0\" class=\"hash-link\" aria-label=\"函数的直接链接\" title=\"函数的直接链接\">​</a></h3>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">func</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">a </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> b </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> a </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+</span><span class=\"token plain\"> b</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"包\">包<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E5%8C%85\" class=\"hash-link\" aria-label=\"包的直接链接\" title=\"包的直接链接\">​</a></h3>\n<p>Go 用目录划分包，例如：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">my-go-app/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── main.go</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">└── utils/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    └── math.go</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p><code>utils/math.go</code>：</p>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> utils</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">func</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">a </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> b </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> a </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+</span><span class=\"token plain\"> b</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>在 <code>main.go</code> 中使用：</p>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"example.com/my-go-app/utils\"</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"五结构体与接口\">五、结构体与接口<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E4%BA%94%E7%BB%93%E6%9E%84%E4%BD%93%E4%B8%8E%E6%8E%A5%E5%8F%A3\" class=\"hash-link\" aria-label=\"五、结构体与接口的直接链接\" title=\"五、结构体与接口的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"结构体struct\">结构体（struct）<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E7%BB%93%E6%9E%84%E4%BD%93struct\" class=\"hash-link\" aria-label=\"结构体（struct）的直接链接\" title=\"结构体（struct）的直接链接\">​</a></h3>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">type</span><span class=\"token plain\"> User </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">struct</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\tName </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\tAge  </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"方法\">方法<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E6%96%B9%E6%B3%95\" class=\"hash-link\" aria-label=\"方法的直接链接\" title=\"方法的直接链接\">​</a></h3>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">func</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">u User</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Greet</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> fmt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Sprintf</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"hi, %s\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> u</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"接口interface\">接口（interface）<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E6%8E%A5%E5%8F%A3interface\" class=\"hash-link\" aria-label=\"接口（interface）的直接链接\" title=\"接口（interface）的直接链接\">​</a></h3>\n<p>接口关注“行为”，而不是具体类型：</p>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">type</span><span class=\"token plain\"> Greeter </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">interface</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Greet</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">func</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">SayHello</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">g Greeter</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\tfmt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Println</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">g</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Greet</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"六并发goroutine-与-channel\">六、并发：goroutine 与 channel<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E5%85%AD%E5%B9%B6%E5%8F%91goroutine-%E4%B8%8E-channel\" class=\"hash-link\" aria-label=\"六、并发：goroutine 与 channel的直接链接\" title=\"六、并发：goroutine 与 channel的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"goroutine\">goroutine<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#goroutine\" class=\"hash-link\" aria-label=\"goroutine的直接链接\" title=\"goroutine的直接链接\">​</a></h3>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">go</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">func</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\tfmt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Println</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"running in goroutine\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"channel-通信\">channel 通信<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#channel-%E9%80%9A%E4%BF%A1\" class=\"hash-link\" aria-label=\"channel 通信的直接链接\" title=\"channel 通信的直接链接\">​</a></h3>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ch </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">make</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">chan</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">go</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">func</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\tch </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;-</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">42</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">v </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:=</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;-</span><span class=\"token plain\">ch</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">fmt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Println</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">v</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"七错误处理\">七、错误处理<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E4%B8%83%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86\" class=\"hash-link\" aria-label=\"七、错误处理的直接链接\" title=\"七、错误处理的直接链接\">​</a></h2>\n<p>Go 的错误处理通常是显式返回 <code>error</code>：</p>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"errors\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">func</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">id </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">error</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> id </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t\t</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> errors</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">New</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"invalid id\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Alice\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">nil</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>调用方：</p>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> err </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> err </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">nil</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\tfmt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Println</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"error:\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> err</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">fmt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Println</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"八http-服务示例\">八、HTTP 服务示例<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E5%85%ABhttp-%E6%9C%8D%E5%8A%A1%E7%A4%BA%E4%BE%8B\" class=\"hash-link\" aria-label=\"八、HTTP 服务示例的直接链接\" title=\"八、HTTP 服务示例的直接链接\">​</a></h2>\n<p>创建 <code>server/main.go</code>：</p>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> main</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"encoding/json\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"net/http\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">func</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">main</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\thttp</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">HandleFunc</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"/health\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">func</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">w http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ResponseWriter</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">_</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\">http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t\tw</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Header</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Set</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Content-Type\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"application/json; charset=utf-8\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t\t</span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">_</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">NewEncoder</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">w</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Encode</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">map</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\">any</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"ok\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\thttp</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ListenAndServe</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\":3000\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">nil</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>运行：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">go run ./server</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>访问：<code>http://localhost:3000/health</code></p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"九测试与工具\">九、测试与工具<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E4%B9%9D%E6%B5%8B%E8%AF%95%E4%B8%8E%E5%B7%A5%E5%85%B7\" class=\"hash-link\" aria-label=\"九、测试与工具的直接链接\" title=\"九、测试与工具的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"基础测试\">基础测试<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E5%9F%BA%E7%A1%80%E6%B5%8B%E8%AF%95\" class=\"hash-link\" aria-label=\"基础测试的直接链接\" title=\"基础测试的直接链接\">​</a></h3>\n<p>在 <code>utils/math_test.go</code>：</p>\n<div class=\"language-go codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-go codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> utils</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"testing\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">func</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">TestAdd</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">t </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\">testing</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">T</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\tgot </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> got </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t\tt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Fatalf</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"expected 3, got %d\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> got</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">\t</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>运行测试：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">go </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">test</span><span class=\"token plain\"> ./</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">.</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十部署与小结\">十、部署与小结<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E5%8D%81%E9%83%A8%E7%BD%B2%E4%B8%8E%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"十、部署与小结的直接链接\" title=\"十、部署与小结的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"构建\">构建<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E6%9E%84%E5%BB%BA\" class=\"hash-link\" aria-label=\"构建的直接链接\" title=\"构建的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">go build </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-o</span><span class=\"token plain\"> app </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">.</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"交叉编译示例\">交叉编译（示例）<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E4%BA%A4%E5%8F%89%E7%BC%96%E8%AF%91%E7%A4%BA%E4%BE%8B\" class=\"hash-link\" aria-label=\"交叉编译（示例）的直接链接\" title=\"交叉编译（示例）的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">GOOS</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">linux </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">GOARCH</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">amd64 go build </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-o</span><span class=\"token plain\"> app </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">.</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"小结\">小结<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"小结的直接链接\" title=\"小结的直接链接\">​</a></h3>\n<ul>\n<li>基础语法：变量、函数、结构体</li>\n<li>工程结构：包与 modules（<code>go.mod</code>）</li>\n<li>设计能力：接口驱动抽象</li>\n<li>并发：goroutine/channel</li>\n<li>网络：net/http 做最小服务</li>\n<li>质量：<code>go test ./...</code></li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十一学习路径小结\">十一、学习路径小结<a href=\"https://xn--qbyt9x.me/blog/go-tutorial#%E5%8D%81%E4%B8%80%E5%AD%A6%E4%B9%A0%E8%B7%AF%E5%BE%84%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"十一、学习路径小结的直接链接\" title=\"十一、学习路径小结的直接链接\">​</a></h2>\n<ol>\n<li>跑通 <code>go mod init</code> 并完成一个 <code>main.go</code></li>\n<li>学会结构体与方法、接口与多态</li>\n<li>写至少一个 goroutine + channel 的例子</li>\n<li>做一个 <code>/health</code> 的 HTTP 服务</li>\n<li>补上测试：至少 1-2 个 <code>go test</code> 用例</li>\n</ol>\n<p>遇到问题可查阅 <a href=\"https://go.dev/doc/\" target=\"_blank\" rel=\"noopener noreferrer\">Go 官方文档</a>。</p>",
            "url": "https://老王.me/blog/go-tutorial",
            "title": "Go 完整教程（新手向）",
            "summary": "由浅入深学习 Go，覆盖基础语法、包与模块、结构体与接口、错误处理、并发（goroutine/channel）、HTTP 服务、测试与部署等主要知识点。",
            "date_modified": "2026-03-19T15:11:56.000Z",
            "tags": []
        },
        {
            "id": "https://老王.me/blog/php-tutorial",
            "content_html": "<p>本教程面向零基础或刚接触 PHP 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"一php-简介\">一、PHP 简介<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E4%B8%80php-%E7%AE%80%E4%BB%8B\" class=\"hash-link\" aria-label=\"一、PHP 简介的直接链接\" title=\"一、PHP 简介的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"php-是什么\">PHP 是什么？<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#php-%E6%98%AF%E4%BB%80%E4%B9%88\" class=\"hash-link\" aria-label=\"PHP 是什么？的直接链接\" title=\"PHP 是什么？的直接链接\">​</a></h3>\n<p>PHP 是一种非常成熟的服务端脚本语言，主要用于构建 Web 应用与后端接口。它的生态非常丰富，常见用途包括：</p>\n<ul>\n<li>动态网页（传统 Web 开发）</li>\n<li>后端 API（REST 风格接口）</li>\n<li>与数据库交互（MySQL/PostgreSQL 等）</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"适合做什么\">适合做什么？<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E9%80%82%E5%90%88%E5%81%9A%E4%BB%80%E4%B9%88\" class=\"hash-link\" aria-label=\"适合做什么？的直接链接\" title=\"适合做什么？的直接链接\">​</a></h3>\n<ul>\n<li>需要快速做出可运行的 Web 服务</li>\n<li>想学习服务端语言的基本开发模式</li>\n<li>对“语法简单 + 生态成熟”有偏好</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"二安装与开发方式\">二、安装与开发方式<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E4%BA%8C%E5%AE%89%E8%A3%85%E4%B8%8E%E5%BC%80%E5%8F%91%E6%96%B9%E5%BC%8F\" class=\"hash-link\" aria-label=\"二、安装与开发方式的直接链接\" title=\"二、安装与开发方式的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"安装-php\">安装 PHP<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E5%AE%89%E8%A3%85-php\" class=\"hash-link\" aria-label=\"安装 PHP的直接链接\" title=\"安装 PHP的直接链接\">​</a></h3>\n<ul>\n<li>选择适合你系统的安装方式（官方安装包、包管理器或集成环境）</li>\n<li>确认版本：</li>\n</ul>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">php </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"本地快速启动内置服务器\">本地快速启动（内置服务器）<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E6%9C%AC%E5%9C%B0%E5%BF%AB%E9%80%9F%E5%90%AF%E5%8A%A8%E5%86%85%E7%BD%AE%E6%9C%8D%E5%8A%A1%E5%99%A8\" class=\"hash-link\" aria-label=\"本地快速启动（内置服务器）的直接链接\" title=\"本地快速启动（内置服务器）的直接链接\">​</a></h3>\n<p>假设你有一个 <code>public/</code> 目录：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">php </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-S</span><span class=\"token plain\"> localhost:8000 </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-t</span><span class=\"token plain\"> public</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>然后访问：<code>http://localhost:8000</code></p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"三基础语法\">三、基础语法<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E4%B8%89%E5%9F%BA%E7%A1%80%E8%AF%AD%E6%B3%95\" class=\"hash-link\" aria-label=\"三、基础语法的直接链接\" title=\"三、基础语法的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"变量与输出\">变量与输出<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E5%8F%98%E9%87%8F%E4%B8%8E%E8%BE%93%E5%87%BA\" class=\"hash-link\" aria-label=\"变量与输出的直接链接\" title=\"变量与输出的直接链接\">​</a></h3>\n<div class=\"language-php codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-php codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token delimiter important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">&lt;?php</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$name</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"Alice\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$age</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">18</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"Hello, </span><span class=\"token string double-quoted-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token string double-quoted-string interpolation variable\" style=\"color:hsl(221, 87%, 60%)\">$name</span><span class=\"token string double-quoted-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\\n\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"Age: </span><span class=\"token string double-quoted-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token string double-quoted-string interpolation variable\" style=\"color:hsl(221, 87%, 60%)\">$age</span><span class=\"token string double-quoted-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\\n\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"条件与循环\">条件与循环<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E6%9D%A1%E4%BB%B6%E4%B8%8E%E5%BE%AA%E7%8E%AF\" class=\"hash-link\" aria-label=\"条件与循环的直接链接\" title=\"条件与循环的直接链接\">​</a></h3>\n<div class=\"language-php codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-php codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token delimiter important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">&lt;?php</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$score</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">90</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$score</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">90</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"A\\n\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"B\\n\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">for</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$i</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$i</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$i</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">++</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">echo</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$i</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">.</span><span class=\"token plain\"> </span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"\\n\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"四函数与作用域\">四、函数与作用域<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E5%9B%9B%E5%87%BD%E6%95%B0%E4%B8%8E%E4%BD%9C%E7%94%A8%E5%9F%9F\" class=\"hash-link\" aria-label=\"四、函数与作用域的直接链接\" title=\"四、函数与作用域的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"定义函数\">定义函数<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E5%AE%9A%E4%B9%89%E5%87%BD%E6%95%B0\" class=\"hash-link\" aria-label=\"定义函数的直接链接\" title=\"定义函数的直接链接\">​</a></h3>\n<div class=\"language-php codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-php codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token delimiter important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">&lt;?php</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function-definition function\" style=\"color:hsl(221, 87%, 60%)\">add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword type-hint\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$a</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword type-hint\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$b</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword return-type\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$a</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$b</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">echo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 3</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"作用域与变量\">作用域与变量<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E4%BD%9C%E7%94%A8%E5%9F%9F%E4%B8%8E%E5%8F%98%E9%87%8F\" class=\"hash-link\" aria-label=\"作用域与变量的直接链接\" title=\"作用域与变量的直接链接\">​</a></h3>\n<p>注意函数内部变量的作用域规则：函数内创建的变量默认不会自动暴露到全局作用域中。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"五面向对象oop\">五、面向对象（OOP）<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E4%BA%94%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1oop\" class=\"hash-link\" aria-label=\"五、面向对象（OOP）的直接链接\" title=\"五、面向对象（OOP）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"类与对象\">类与对象<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E7%B1%BB%E4%B8%8E%E5%AF%B9%E8%B1%A1\" class=\"hash-link\" aria-label=\"类与对象的直接链接\" title=\"类与对象的直接链接\">​</a></h3>\n<div class=\"language-php codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-php codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token delimiter important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">&lt;?php</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name-definition class-name\" style=\"color:hsl(35, 99%, 36%)\">User</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">public</span><span class=\"token plain\"> </span><span class=\"token keyword type-declaration\" style=\"color:hsl(301, 63%, 40%)\">string</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">public</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function-definition function\" style=\"color:hsl(221, 87%, 60%)\">__construct</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword type-hint\" style=\"color:hsl(301, 63%, 40%)\">string</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$this</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-&gt;</span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">name</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">public</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function-definition function\" style=\"color:hsl(221, 87%, 60%)\">greet</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword return-type\" style=\"color:hsl(301, 63%, 40%)\">string</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"hi, </span><span class=\"token string double-quoted-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token string double-quoted-string interpolation variable\" style=\"color:hsl(221, 87%, 60%)\">$this</span><span class=\"token string double-quoted-string interpolation operator\" style=\"color:hsl(221, 87%, 60%)\">-&gt;</span><span class=\"token string double-quoted-string interpolation property\" style=\"color:hsl(5, 74%, 59%)\">name</span><span class=\"token string double-quoted-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$u</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">new</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">User</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"Tom\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">echo</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$u</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-&gt;</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">greet</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"继承了解\">继承（了解）<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E7%BB%A7%E6%89%BF%E4%BA%86%E8%A7%A3\" class=\"hash-link\" aria-label=\"继承（了解）的直接链接\" title=\"继承（了解）的直接链接\">​</a></h3>\n<div class=\"language-php codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-php codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token delimiter important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">&lt;?php</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name-definition class-name\" style=\"color:hsl(35, 99%, 36%)\">Admin</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">extends</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">User</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">public</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function-definition function\" style=\"color:hsl(221, 87%, 60%)\">role</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword return-type\" style=\"color:hsl(301, 63%, 40%)\">string</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"admin\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"六命名空间与-composer包管理\">六、命名空间与 Composer（包管理）<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E5%85%AD%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E4%B8%8E-composer%E5%8C%85%E7%AE%A1%E7%90%86\" class=\"hash-link\" aria-label=\"六、命名空间与 Composer（包管理）的直接链接\" title=\"六、命名空间与 Composer（包管理）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"安装-composer\">安装 Composer<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E5%AE%89%E8%A3%85-composer\" class=\"hash-link\" aria-label=\"安装 Composer的直接链接\" title=\"安装 Composer的直接链接\">​</a></h3>\n<ul>\n<li>进入官网安装 Composer（或使用系统包管理器）</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"初始化项目与引入依赖\">初始化项目与引入依赖<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E5%88%9D%E5%A7%8B%E5%8C%96%E9%A1%B9%E7%9B%AE%E4%B8%8E%E5%BC%95%E5%85%A5%E4%BE%9D%E8%B5%96\" class=\"hash-link\" aria-label=\"初始化项目与引入依赖的直接链接\" title=\"初始化项目与引入依赖的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">composer</span><span class=\"token plain\"> init</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">composer</span><span class=\"token plain\"> require guzzlehttp/guzzle</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>然后即可在代码中使用第三方库（具体 API 以库文档为准）。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"七数据库pdo-简例\">七、数据库（PDO 简例）<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E4%B8%83%E6%95%B0%E6%8D%AE%E5%BA%93pdo-%E7%AE%80%E4%BE%8B\" class=\"hash-link\" aria-label=\"七、数据库（PDO 简例）的直接链接\" title=\"七、数据库（PDO 简例）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"pdo-基础连接\">PDO 基础连接<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#pdo-%E5%9F%BA%E7%A1%80%E8%BF%9E%E6%8E%A5\" class=\"hash-link\" aria-label=\"PDO 基础连接的直接链接\" title=\"PDO 基础连接的直接链接\">​</a></h3>\n<div class=\"language-php codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-php codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token delimiter important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">&lt;?php</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$dsn</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"mysql:host=localhost;dbname=mydb;charset=utf8mb4\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$user</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"root\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$password</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"xxx\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$pdo</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">new</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">PDO</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$dsn</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$password</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token class-name static-context\" style=\"color:hsl(35, 99%, 36%)\">PDO</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">::</span><span class=\"token constant\" style=\"color:hsl(35, 99%, 36%)\">ATTR_ERRMODE</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token class-name static-context\" style=\"color:hsl(35, 99%, 36%)\">PDO</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">::</span><span class=\"token constant\" style=\"color:hsl(35, 99%, 36%)\">ERRMODE_EXCEPTION</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"使用预处理防-sql-注入\">使用预处理（防 SQL 注入）<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E4%BD%BF%E7%94%A8%E9%A2%84%E5%A4%84%E7%90%86%E9%98%B2-sql-%E6%B3%A8%E5%85%A5\" class=\"hash-link\" aria-label=\"使用预处理（防 SQL 注入）的直接链接\" title=\"使用预处理（防 SQL 注入）的直接链接\">​</a></h3>\n<div class=\"language-php codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-php codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token delimiter important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">&lt;?php</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$stmt</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$pdo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-&gt;</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">prepare</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"SELECT * FROM users WHERE id = :id\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$stmt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-&gt;</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">execute</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string single-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">':id'</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$row</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$stmt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-&gt;</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">fetch</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token class-name static-context\" style=\"color:hsl(35, 99%, 36%)\">PDO</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">::</span><span class=\"token constant\" style=\"color:hsl(35, 99%, 36%)\">FETCH_ASSOC</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">var_dump</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$row</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"八简单-web-服务示例路由思路\">八、简单 Web 服务示例（路由思路）<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E5%85%AB%E7%AE%80%E5%8D%95-web-%E6%9C%8D%E5%8A%A1%E7%A4%BA%E4%BE%8B%E8%B7%AF%E7%94%B1%E6%80%9D%E8%B7%AF\" class=\"hash-link\" aria-label=\"八、简单 Web 服务示例（路由思路）的直接链接\" title=\"八、简单 Web 服务示例（路由思路）的直接链接\">​</a></h2>\n<p>你可以用“单入口文件”来做最基础的路由分发（新手学习用）：</p>\n<p><code>public/index.php</code>：</p>\n<div class=\"language-php codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-php codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token delimiter important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">&lt;?php</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$path</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">parse_url</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$_SERVER</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string single-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">'REQUEST_URI'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token constant\" style=\"color:hsl(35, 99%, 36%)\">PHP_URL_PATH</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$path</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">===</span><span class=\"token plain\"> </span><span class=\"token string single-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">'/health'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">header</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string single-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">'Content-Type: application/json; charset=utf-8'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">echo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">json_encode</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string single-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">'ok'</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=&gt;</span><span class=\"token plain\"> </span><span class=\"token constant boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token constant\" style=\"color:hsl(35, 99%, 36%)\">JSON_UNESCAPED_UNICODE</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">exit</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">http_response_code</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">404</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string double-quoted-string\" style=\"color:hsl(119, 34%, 47%)\">\"Not Found\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>启动后访问：<code>/health</code></p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"九测试与质量\">九、测试与质量<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E4%B9%9D%E6%B5%8B%E8%AF%95%E4%B8%8E%E8%B4%A8%E9%87%8F\" class=\"hash-link\" aria-label=\"九、测试与质量的直接链接\" title=\"九、测试与质量的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"安装-phpunit\">安装 PHPUnit<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E5%AE%89%E8%A3%85-phpunit\" class=\"hash-link\" aria-label=\"安装 PHPUnit的直接链接\" title=\"安装 PHPUnit的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">composer</span><span class=\"token plain\"> require </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--dev</span><span class=\"token plain\"> phpunit/phpunit</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>写一个简单测试：<code>tests/MathTest.php</code></p>\n<div class=\"language-php codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-php codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token delimiter important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">&lt;?php</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">use</span><span class=\"token plain\"> </span><span class=\"token package\">PHPUnit</span><span class=\"token package punctuation\" style=\"color:hsl(119, 34%, 47%)\">\\</span><span class=\"token package\">Framework</span><span class=\"token package punctuation\" style=\"color:hsl(119, 34%, 47%)\">\\</span><span class=\"token package\">TestCase</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">final</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token class-name-definition class-name\" style=\"color:hsl(35, 99%, 36%)\">MathTest</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">extends</span><span class=\"token plain\"> </span><span class=\"token class-name\" style=\"color:hsl(35, 99%, 36%)\">TestCase</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">public</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function-definition function\" style=\"color:hsl(221, 87%, 60%)\">testAdd</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword return-type\" style=\"color:hsl(301, 63%, 40%)\">void</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$this</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-&gt;</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">assertSame</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>运行：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">vendor/bin/phpunit</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十部署与小结\">十、部署与小结<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E5%8D%81%E9%83%A8%E7%BD%B2%E4%B8%8E%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"十、部署与小结的直接链接\" title=\"十、部署与小结的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"部署思路\">部署思路<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E9%83%A8%E7%BD%B2%E6%80%9D%E8%B7%AF\" class=\"hash-link\" aria-label=\"部署思路的直接链接\" title=\"部署思路的直接链接\">​</a></h3>\n<ul>\n<li>生产环境使用稳定的 Web 服务器（Nginx + PHP-FPM 等）</li>\n<li>配置环境变量（数据库连接、密钥等）</li>\n<li>使用 Composer 管理依赖并做出可复现的构建</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"小结\">小结<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"小结的直接链接\" title=\"小结的直接链接\">​</a></h3>\n<ul>\n<li>语法基础：变量、条件、循环、函数</li>\n<li>工程能力：Composer、命名空间</li>\n<li>数据：PDO + 预处理</li>\n<li>Web：最小路由示例</li>\n<li>质量：PHPUnit</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十一学习路径小结\">十一、学习路径小结<a href=\"https://xn--qbyt9x.me/blog/php-tutorial#%E5%8D%81%E4%B8%80%E5%AD%A6%E4%B9%A0%E8%B7%AF%E5%BE%84%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"十一、学习路径小结的直接链接\" title=\"十一、学习路径小结的直接链接\">​</a></h2>\n<ol>\n<li>跑通 <code>php -S</code> 并写一个 <code>/health</code> 接口</li>\n<li>掌握基础语法与函数（至少 3-5 个练习题）</li>\n<li>学会 OOP 并写一个 <code>User</code> 类</li>\n<li>使用 Composer 引入一个库，并写一次调用</li>\n<li>用 PDO 写一个带预处理的查询示例</li>\n<li>最少写 1 个 PHPUnit 测试并运行通过</li>\n</ol>\n<p>遇到问题可查阅 <a href=\"https://www.php.net/docs.php\" target=\"_blank\" rel=\"noopener noreferrer\">PHP 官方文档</a>。</p>",
            "url": "https://老王.me/blog/php-tutorial",
            "title": "PHP 完整教程（新手向）",
            "summary": "由浅入深学习 PHP，覆盖基础语法、面向对象、Composer 与包管理、PDO 数据访问、简单 Web 服务、测试与部署等主要知识点。",
            "date_modified": "2026-03-19T15:11:56.000Z",
            "tags": []
        },
        {
            "id": "https://老王.me/blog/docusaurus-tutorial",
            "content_html": "<p>本教程面向零基础或刚接触 Docusaurus 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"一docusaurus-简介\">一、Docusaurus 简介<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E4%B8%80docusaurus-%E7%AE%80%E4%BB%8B\" class=\"hash-link\" aria-label=\"一、Docusaurus 简介的直接链接\" title=\"一、Docusaurus 简介的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"什么是-docusaurus\">什么是 Docusaurus？<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E4%BB%80%E4%B9%88%E6%98%AF-docusaurus\" class=\"hash-link\" aria-label=\"什么是 Docusaurus？的直接链接\" title=\"什么是 Docusaurus？的直接链接\">​</a></h3>\n<p>Docusaurus 是 <strong>Meta（Facebook）开源</strong> 的静态站点生成器，专门为 <strong>文档站、博客、产品主页</strong> 设计。特点包括：</p>\n<ul>\n<li><strong>基于 React</strong>：可嵌入 React 组件，扩展性强</li>\n<li><strong>Markdown / MDX 优先</strong>：用熟悉的 Markdown 写文档，支持 JSX</li>\n<li><strong>开箱即用</strong>：侧边栏、导航、搜索、深色模式、多语言等内置</li>\n<li><strong>静态站点</strong>：构建后是纯 HTML/CSS/JS，易部署、速度快</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"适合做什么\">适合做什么？<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E9%80%82%E5%90%88%E5%81%9A%E4%BB%80%E4%B9%88\" class=\"hash-link\" aria-label=\"适合做什么？的直接链接\" title=\"适合做什么？的直接链接\">​</a></h3>\n<ul>\n<li>产品/API 文档</li>\n<li>技术博客</li>\n<li>开源项目说明站</li>\n<li>团队知识库</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"二环境准备与创建项目\">二、环境准备与创建项目<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E4%BA%8C%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87%E4%B8%8E%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"二、环境准备与创建项目的直接链接\" title=\"二、环境准备与创建项目的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"环境要求\">环境要求<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E7%8E%AF%E5%A2%83%E8%A6%81%E6%B1%82\" class=\"hash-link\" aria-label=\"环境要求的直接链接\" title=\"环境要求的直接链接\">​</a></h3>\n<ul>\n<li><strong>Node.js</strong>：建议 20.0 及以上（LTS 即可）</li>\n<li><strong>包管理器</strong>：npm / yarn / pnpm 任选其一</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"创建新项目\">创建新项目<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E5%88%9B%E5%BB%BA%E6%96%B0%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"创建新项目的直接链接\" title=\"创建新项目的直接链接\">​</a></h3>\n<p>使用官方脚手架（经典模板）：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> init docusaurus@latest my-website classic</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>按提示选择：</p>\n<ul>\n<li><strong>模板</strong>：<code>classic</code>（包含文档 + 博客）</li>\n<li>是否使用 TypeScript：按需选择</li>\n</ul>\n<p>进入项目并启动开发服务器：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> my-website</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run start</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>在浏览器打开 <strong><a href=\"http://localhost:3000/\" target=\"_blank\" rel=\"noopener noreferrer\">http://localhost:3000</a></strong> 即可看到默认站点。</p>\n<div class=\"theme-admonition theme-admonition-tip admonition_fh9h alert alert--success\"><div class=\"admonitionHeading__rZX\"><span class=\"admonitionIcon_krpS\"><svg viewBox=\"0 0 12 16\"><path fill-rule=\"evenodd\" d=\"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z\"></path></svg></span>WSL / 远程开发</div><div class=\"admonitionContent_oz3Y\"><p>若在 WSL 中运行、用 Windows 浏览器访问，需让开发服务器监听所有网卡。在 <code>package.json</code> 中把启动脚本改为：</p><div class=\"language-json codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-json codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"start\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"docusaurus start --host 0.0.0.0\"</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div><p>然后可用 WSL 的 IP 访问，如 <code>http://172.x.x.x:3000</code>。</p></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"三项目目录结构\">三、项目目录结构<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E4%B8%89%E9%A1%B9%E7%9B%AE%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84\" class=\"hash-link\" aria-label=\"三、项目目录结构的直接链接\" title=\"三、项目目录结构的直接链接\">​</a></h2>\n<p>理解目录结构有助于后续自定义和排查问题。</p>\n<div class=\"language-javascript codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-javascript codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">my</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-</span><span class=\"token plain\">website</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── blog</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token plain\">                 # 博客文章（按日期或文件夹组织）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── docs</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token plain\">                 # 文档源文件（Markdown</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token constant\" style=\"color:hsl(35, 99%, 36%)\">MDX</span><span class=\"token plain\">）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── src</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── components</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token plain\">       # 自定义 </span><span class=\"token maybe-class-name\">React</span><span class=\"token plain\"> 组件</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── css</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token plain\">              # 全局样式（如 custom</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">css）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   └── pages</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token plain\">            # 独立页面，对应站点路由</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">static</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token plain\">               # 静态资源（图片、favicon 等），会原样复制到站点根目录</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── docusaurus</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">config</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">ts</span><span class=\"token plain\">  # 站点主配置</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── sidebars</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">ts</span><span class=\"token plain\">           # 文档侧边栏配置</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">└── </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token property-access\">json</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>重点目录说明：</p>\n<table><thead><tr><th>目录/文件</th><th>作用</th></tr></thead><tbody><tr><td><code>docs/</code></td><td>所有「文档」类页面，自动参与侧边栏与导航</td></tr><tr><td><code>blog/</code></td><td>博客文章，自动按时间列表与归档</td></tr><tr><td><code>src/pages/</code></td><td>自定义页面，每个文件对应一个路由（如 <code>about.js</code> → <code>/about</code>）</td></tr><tr><td><code>static/</code></td><td>放图片、PDF 等，引用时路径从根写起，如 <code>/img/logo.png</code></td></tr><tr><td><code>docusaurus.config.ts</code></td><td>站点标题、URL、主题、插件、导航栏、页脚等</td></tr><tr><td><code>sidebars.ts</code></td><td>文档侧边栏顺序与分组</td></tr></tbody></table>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"四编写文档docs\">四、编写文档（docs）<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E5%9B%9B%E7%BC%96%E5%86%99%E6%96%87%E6%A1%A3docs\" class=\"hash-link\" aria-label=\"四、编写文档（docs）的直接链接\" title=\"四、编写文档（docs）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"41-新建一篇文档\">4.1 新建一篇文档<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#41-%E6%96%B0%E5%BB%BA%E4%B8%80%E7%AF%87%E6%96%87%E6%A1%A3\" class=\"hash-link\" aria-label=\"4.1 新建一篇文档的直接链接\" title=\"4.1 新建一篇文档的直接链接\">​</a></h3>\n<p>在 <code>docs/</code> 下新建任意 <code>.md</code> 或 <code>.mdx</code> 文件即可，例如：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 例如</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">docs/quick-start.md</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">docs/guide/install.md</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>文件顶部可写 <strong>Front Matter</strong>（YAML），用于配置当前页在侧边栏和 SEO 等行为。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"42-front-matter-常用字段\">4.2 Front Matter 常用字段<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#42-front-matter-%E5%B8%B8%E7%94%A8%E5%AD%97%E6%AE%B5\" class=\"hash-link\" aria-label=\"4.2 Front Matter 常用字段的直接链接\" title=\"4.2 Front Matter 常用字段的直接链接\">​</a></h3>\n<div class=\"language-yaml codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-yaml codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">---</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 侧边栏显示的文字（默认用标题）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">sidebar_label</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 快速开始</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 侧边栏中的排序，数字越小越靠前</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">sidebar_position</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 页面标题（浏览器标签、SEO）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">title</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 快速开始</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 页面描述（SEO）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">description</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 5 分钟上手 Docusaurus</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 自定义 URL 最后一段，默认用文件名</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">slug</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> /quick</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">start</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 是否在侧边栏中隐藏</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">sidebar_class_name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 可选 CSS 类名</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">---</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>示例：</p>\n<div class=\"language-md codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">docs/quick-start.md<span style=\"flex:1;text-align:right\">md</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-md codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token front-matter-block punctuation\" style=\"color:hsl(119, 34%, 47%)\">---</span><span class=\"token front-matter-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token front-matter-block\"></span><span class=\"token front-matter-block front-matter yaml language-yaml key atrule\" style=\"color:hsl(35, 99%, 36%)\">sidebar_label</span><span class=\"token front-matter-block front-matter yaml language-yaml punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token front-matter-block front-matter yaml language-yaml\"> 快速开始</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token front-matter-block front-matter yaml language-yaml\"></span><span class=\"token front-matter-block front-matter yaml language-yaml key atrule\" style=\"color:hsl(35, 99%, 36%)\">sidebar_position</span><span class=\"token front-matter-block front-matter yaml language-yaml punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token front-matter-block front-matter yaml language-yaml\"> </span><span class=\"token front-matter-block front-matter yaml language-yaml number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token front-matter-block front-matter yaml language-yaml\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token front-matter-block front-matter yaml language-yaml\"></span><span class=\"token front-matter-block front-matter yaml language-yaml key atrule\" style=\"color:hsl(35, 99%, 36%)\">title</span><span class=\"token front-matter-block front-matter yaml language-yaml punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token front-matter-block front-matter yaml language-yaml\"> 快速开始</span><span class=\"token front-matter-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token front-matter-block\"></span><span class=\"token front-matter-block punctuation\" style=\"color:hsl(119, 34%, 47%)\">---</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token title important punctuation\" style=\"color:hsl(119, 34%, 47%);font-weight:bold\">#</span><span class=\"token title important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\"> 快速开始</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">这里是正文……</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>保存后，开发服务器会热更新，文档会出现在侧边栏并可按 <code>sidebar_position</code> 排序。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"43-文档之间的链接\">4.3 文档之间的链接<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#43-%E6%96%87%E6%A1%A3%E4%B9%8B%E9%97%B4%E7%9A%84%E9%93%BE%E6%8E%A5\" class=\"hash-link\" aria-label=\"4.3 文档之间的链接的直接链接\" title=\"4.3 文档之间的链接的直接链接\">​</a></h3>\n<ul>\n<li><strong>站内文档</strong>：用 Markdown 链接到相对路径或绝对路径均可。</li>\n</ul>\n<div class=\"language-md codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-md codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token url\" style=\"color:hsl(198, 99%, 37%)\">[</span><span class=\"token url content\" style=\"color:hsl(198, 99%, 37%)\">安装说明</span><span class=\"token url\" style=\"color:hsl(198, 99%, 37%)\">](</span><span class=\"token url\" style=\"color:hsl(198, 99%, 37%)\">./install</span><span class=\"token url\" style=\"color:hsl(198, 99%, 37%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token url\" style=\"color:hsl(198, 99%, 37%)\">[</span><span class=\"token url content\" style=\"color:hsl(198, 99%, 37%)\">介绍</span><span class=\"token url\" style=\"color:hsl(198, 99%, 37%)\">](</span><span class=\"token url\" style=\"color:hsl(198, 99%, 37%)\">/docs/intro</span><span class=\"token url\" style=\"color:hsl(198, 99%, 37%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<ul>\n<li><strong>推荐</strong>：使用 Docusaurus 的「文档链接」语法，便于以后改 path 时统一替换：</li>\n</ul>\n<div class=\"language-md codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-md codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token url\" style=\"color:hsl(198, 99%, 37%)\">[</span><span class=\"token url content\" style=\"color:hsl(198, 99%, 37%)\">介绍</span><span class=\"token url\" style=\"color:hsl(198, 99%, 37%)\">](</span><span class=\"token url\" style=\"color:hsl(198, 99%, 37%)\">intro.md</span><span class=\"token url\" style=\"color:hsl(198, 99%, 37%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"五侧边栏sidebar配置\">五、侧边栏（Sidebar）配置<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E4%BA%94%E4%BE%A7%E8%BE%B9%E6%A0%8Fsidebar%E9%85%8D%E7%BD%AE\" class=\"hash-link\" aria-label=\"五、侧边栏（Sidebar）配置的直接链接\" title=\"五、侧边栏（Sidebar）配置的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"51-自动生成默认\">5.1 自动生成（默认）<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#51-%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E9%BB%98%E8%AE%A4\" class=\"hash-link\" aria-label=\"5.1 自动生成（默认）的直接链接\" title=\"5.1 自动生成（默认）的直接链接\">​</a></h3>\n<p>在 <code>sidebars.ts</code> 中常见写法：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> sidebars</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> SidebarsConfig </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  tutorialSidebar</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'autogenerated'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> dirName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'.'</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>表示根据 <code>docs/</code> 的<strong>目录和文件名</strong>自动生成侧边栏，顺序由各文档的 <code>sidebar_position</code> 和文件名共同决定。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"52-用文件夹分组分类\">5.2 用文件夹分组（分类）<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#52-%E7%94%A8%E6%96%87%E4%BB%B6%E5%A4%B9%E5%88%86%E7%BB%84%E5%88%86%E7%B1%BB\" class=\"hash-link\" aria-label=\"5.2 用文件夹分组（分类）的直接链接\" title=\"5.2 用文件夹分组（分类）的直接链接\">​</a></h3>\n<p>在 <code>docs/</code> 下建子文件夹，并在该文件夹内放一个 <code>_category_.json</code> 即可成为一个「分类」：</p>\n<div class=\"language-json codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-json codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// docs/guide/_category_.json</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"label\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"使用指南\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"position\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"link\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"type\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"generated-index\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"title\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"指南索引\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"description\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"按主题查阅使用说明。\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<ul>\n<li><code>label</code>：侧边栏中显示的分类名</li>\n<li><code>position</code>：分类在侧边栏中的顺序</li>\n<li><code>link</code>：可选，点分类名时进入「索引页」</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"53-手动配置侧边栏\">5.3 手动配置侧边栏<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#53-%E6%89%8B%E5%8A%A8%E9%85%8D%E7%BD%AE%E4%BE%A7%E8%BE%B9%E6%A0%8F\" class=\"hash-link\" aria-label=\"5.3 手动配置侧边栏的直接链接\" title=\"5.3 手动配置侧边栏的直接链接\">​</a></h3>\n<p>若需要完全自定义顺序和结构，可在 <code>sidebars.ts</code> 中手写：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> sidebars</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> SidebarsConfig </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  tutorialSidebar</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'intro'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'quick-start'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'category'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      label</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'使用指南'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      items</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'guide/install'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'guide/usage'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<ul>\n<li>字符串：对应 <code>docs/</code> 下的文档 ID（通常为不含扩展名的路径）</li>\n<li><code>type: 'category'</code>：分组，<code>items</code> 为子文档列表</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"六markdown-与-mdx\">六、Markdown 与 MDX<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E5%85%ADmarkdown-%E4%B8%8E-mdx\" class=\"hash-link\" aria-label=\"六、Markdown 与 MDX的直接链接\" title=\"六、Markdown 与 MDX的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"61-支持的-markdown-语法\">6.1 支持的 Markdown 语法<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#61-%E6%94%AF%E6%8C%81%E7%9A%84-markdown-%E8%AF%AD%E6%B3%95\" class=\"hash-link\" aria-label=\"6.1 支持的 Markdown 语法的直接链接\" title=\"6.1 支持的 Markdown 语法的直接链接\">​</a></h3>\n<p>Docusaurus 使用 <strong>MDX</strong>（Markdown + JSX），所以普通 Markdown 都支持，例如：</p>\n<ul>\n<li>标题、列表、引用、表格</li>\n<li><strong>粗体</strong>、<em>斜体</em>、<code>代码</code></li>\n<li>链接、图片</li>\n<li>代码块（带语法高亮）</li>\n</ul>\n<p>代码块可指定语言和标题：</p>\n<div class=\"language-md codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-md codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token code punctuation\" style=\"color:hsl(119, 34%, 47%)\">```</span><span class=\"token code code-language\">js title=\"utils.js\"</span><span class=\"token code\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token code\"></span><span class=\"token code code-block language-js\">export function add(a, b) {</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token code code-block language-js\">  return a + b;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token code code-block language-js\">}</span><span class=\"token code\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token code\"></span><span class=\"token code punctuation\" style=\"color:hsl(119, 34%, 47%)\">```</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"62-使用-admonition提示框\">6.2 使用 Admonition（提示框）<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#62-%E4%BD%BF%E7%94%A8-admonition%E6%8F%90%E7%A4%BA%E6%A1%86\" class=\"hash-link\" aria-label=\"6.2 使用 Admonition（提示框）的直接链接\" title=\"6.2 使用 Admonition（提示框）的直接链接\">​</a></h3>\n<p>内置的「提示框」组件，适合做说明、注意、警告等：</p>\n<div class=\"language-md codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-md codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">:::note[说明]</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">这是一段说明文字。</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">:::</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">:::tip[提示]</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">小技巧。</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">:::</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">:::danger[注意]</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">谨慎操作。</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">:::</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">:::info[信息]</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">补充信息。</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">:::</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">:::caution[警告]</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">可能带来的风险。</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">:::</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"63-在-mdx-中使用-react-组件\">6.3 在 MDX 中使用 React 组件<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#63-%E5%9C%A8-mdx-%E4%B8%AD%E4%BD%BF%E7%94%A8-react-%E7%BB%84%E4%BB%B6\" class=\"hash-link\" aria-label=\"6.3 在 MDX 中使用 React 组件的直接链接\" title=\"6.3 在 MDX 中使用 React 组件的直接链接\">​</a></h3>\n<p>文件扩展名改为 <code>.mdx</code> 后，可直接写 JSX：</p>\n<div class=\"language-mdx codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-mdx codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">import MyComponent from '@site/src/components/MyComponent';</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">## 章节标题</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">普通 Markdown 内容……</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">&lt;MyComponent name=\"Docusaurus\" /&gt;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>可引入 <code>src/components/</code> 下的自定义组件，或 Docusaurus 内置组件（如 <code>TOCInline</code>、<code>CodeBlock</code> 等）。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"64-在-markdown-中插入-jsx不换-mdx\">6.4 在 Markdown 中插入 JSX（不换 .mdx）<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#64-%E5%9C%A8-markdown-%E4%B8%AD%E6%8F%92%E5%85%A5-jsx%E4%B8%8D%E6%8D%A2-mdx\" class=\"hash-link\" aria-label=\"6.4 在 Markdown 中插入 JSX（不换 .mdx）的直接链接\" title=\"6.4 在 Markdown 中插入 JSX（不换 .mdx）的直接链接\">​</a></h3>\n<p>若保持 <code>.md</code> 扩展名，仍可使用部分「类似 HTML」的写法，但复杂组件建议用 <code>.mdx</code> 并 <code>import</code>。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"七博客blog\">七、博客（Blog）<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E4%B8%83%E5%8D%9A%E5%AE%A2blog\" class=\"hash-link\" aria-label=\"七、博客（Blog）的直接链接\" title=\"七、博客（Blog）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"71-文章放在哪\">7.1 文章放在哪<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#71-%E6%96%87%E7%AB%A0%E6%94%BE%E5%9C%A8%E5%93%AA\" class=\"hash-link\" aria-label=\"7.1 文章放在哪的直接链接\" title=\"7.1 文章放在哪的直接链接\">​</a></h3>\n<ul>\n<li><strong>方式一</strong>：直接在 <code>blog/</code> 下放 <code>YYYY-MM-DD-标题.md</code></li>\n<li><strong>方式二</strong>：在 <code>blog/</code> 下建子文件夹，如 <code>blog/2024/03/15-hello.md</code></li>\n</ul>\n<p>文件名中的日期会用于排序和 URL。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"72-博客-front-matter\">7.2 博客 Front Matter<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#72-%E5%8D%9A%E5%AE%A2-front-matter\" class=\"hash-link\" aria-label=\"7.2 博客 Front Matter的直接链接\" title=\"7.2 博客 Front Matter的直接链接\">​</a></h3>\n<div class=\"language-yaml codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-yaml codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">---</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">slug</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> my</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">first</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">post</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">title</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 我的第一篇文章</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">authors</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">slorber</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">tags</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">hello</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> docusaurus</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">date</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token datetime number\" style=\"color:hsl(35, 99%, 36%)\">2024-03-15</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">---</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">正文……</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<ul>\n<li><code>authors</code>：对应 <code>blog/authors.yml</code> 中定义的作者 ID</li>\n<li><code>tags</code>：标签，可在 <code>blog/tags.yml</code> 中定义</li>\n<li><code>date</code>：发布日期</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"73-关闭或自定义博客\">7.3 关闭或自定义博客<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#73-%E5%85%B3%E9%97%AD%E6%88%96%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8D%9A%E5%AE%A2\" class=\"hash-link\" aria-label=\"7.3 关闭或自定义博客的直接链接\" title=\"7.3 关闭或自定义博客的直接链接\">​</a></h3>\n<p>在 <code>docusaurus.config.ts</code> 的 preset 中可关闭博客或改路径：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">presets</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'classic'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      blog</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        path</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'news'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 博客路径改为 /news</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        showReadingTime</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        blogTitle</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'动态'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"八自定义页面srcpages\">八、自定义页面（src/pages）<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E5%85%AB%E8%87%AA%E5%AE%9A%E4%B9%89%E9%A1%B5%E9%9D%A2srcpages\" class=\"hash-link\" aria-label=\"八、自定义页面（src/pages）的直接链接\" title=\"八、自定义页面（src/pages）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"81-约定式路由\">8.1 约定式路由<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#81-%E7%BA%A6%E5%AE%9A%E5%BC%8F%E8%B7%AF%E7%94%B1\" class=\"hash-link\" aria-label=\"8.1 约定式路由的直接链接\" title=\"8.1 约定式路由的直接链接\">​</a></h3>\n<p><code>src/pages/</code> 下的文件会变成站点路由：</p>\n<ul>\n<li><code>src/pages/index.js</code> → <code>/</code></li>\n<li><code>src/pages/about.js</code> → <code>/about</code></li>\n<li><code>src/pages/help/index.js</code> → <code>/help</code></li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"82-页面写法\">8.2 页面写法<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#82-%E9%A1%B5%E9%9D%A2%E5%86%99%E6%B3%95\" class=\"hash-link\" aria-label=\"8.2 页面写法的直接链接\" title=\"8.2 页面写法的直接链接\">​</a></h3>\n<p>可以是 React 函数组件，导出默认组件即可：</p>\n<div class=\"language-jsx codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-jsx codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// src/pages/about.js</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword module\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token imports maybe-class-name\">React</span><span class=\"token plain\"> </span><span class=\"token keyword module\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'react'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword module\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token imports maybe-class-name\">Layout</span><span class=\"token plain\"> </span><span class=\"token keyword module\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@theme/Layout'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword module\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword module\" style=\"color:hsl(301, 63%, 40%)\">default</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function maybe-class-name\" style=\"color:hsl(221, 87%, 60%)\">About</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword control-flow\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag class-name\" style=\"color:hsl(35, 99%, 36%)\">Layout</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token tag attr-name\" style=\"color:hsl(35, 99%, 36%)\">title</span><span class=\"token tag attr-value punctuation attr-equals\" style=\"color:hsl(119, 34%, 47%)\">=</span><span class=\"token tag attr-value punctuation\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token tag attr-value\" style=\"color:hsl(119, 34%, 47%)\">关于</span><span class=\"token tag attr-value punctuation\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token tag attr-name\" style=\"color:hsl(35, 99%, 36%)\">description</span><span class=\"token tag attr-value punctuation attr-equals\" style=\"color:hsl(119, 34%, 47%)\">=</span><span class=\"token tag attr-value punctuation\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token tag attr-value\" style=\"color:hsl(119, 34%, 47%)\">关于本站</span><span class=\"token tag attr-value punctuation\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">      </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">main</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">        </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">h1</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\">关于我们</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">h1</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">        </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">p</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\">这里是关于页内容。</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">p</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">      </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">main</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">    </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag class-name\" style=\"color:hsl(35, 99%, 36%)\">Layout</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>使用 <code>&lt;Layout&gt;</code> 可保持与全站一致的导航栏、侧边栏和页脚。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"83-覆盖首页\">8.3 覆盖首页<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#83-%E8%A6%86%E7%9B%96%E9%A6%96%E9%A1%B5\" class=\"hash-link\" aria-label=\"8.3 覆盖首页的直接链接\" title=\"8.3 覆盖首页的直接链接\">​</a></h3>\n<p>若想完全自定义首页，可修改或替换 <code>src/pages/index.js</code>，或通过 <code>docusaurus.config.ts</code> 的 <code>plugins</code> 配置首页路由。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"九导航栏与页脚\">九、导航栏与页脚<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E4%B9%9D%E5%AF%BC%E8%88%AA%E6%A0%8F%E4%B8%8E%E9%A1%B5%E8%84%9A\" class=\"hash-link\" aria-label=\"九、导航栏与页脚的直接链接\" title=\"九、导航栏与页脚的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"91-导航栏navbar\">9.1 导航栏（navbar）<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#91-%E5%AF%BC%E8%88%AA%E6%A0%8Fnavbar\" class=\"hash-link\" aria-label=\"9.1 导航栏（navbar）的直接链接\" title=\"9.1 导航栏（navbar）的直接链接\">​</a></h3>\n<p>在 <code>docusaurus.config.ts</code> 的 <code>themeConfig.navbar</code> 中配置：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">themeConfig</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  navbar</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    title</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'我的站点'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    logo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      alt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Logo'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      src</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'img/logo.svg'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    items</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'docSidebar'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> sidebarId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'tutorialSidebar'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> label</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'文档'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> position</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'left'</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> to</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'/blog'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> label</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'博客'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> position</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'left'</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'docsVersionDropdown'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> position</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'right'</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'localeDropdown'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> position</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'right'</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> href</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'https://github.com/xxx'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> label</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'GitHub'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> position</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'right'</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<ul>\n<li><code>docSidebar</code>：指向某个侧边栏（文档入口）</li>\n<li><code>to</code>：站内路径</li>\n<li><code>href</code>：站外链接</li>\n<li><code>docsVersionDropdown</code> / <code>localeDropdown</code>：版本、语言下拉（需先启用对应功能）</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"92-页脚footer\">9.2 页脚（footer）<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#92-%E9%A1%B5%E8%84%9Afooter\" class=\"hash-link\" aria-label=\"9.2 页脚（footer）的直接链接\" title=\"9.2 页脚（footer）的直接链接\">​</a></h3>\n<p>在 <code>themeConfig.footer</code> 中配置链接和版权信息，结构与 <code>navbar</code> 类似，可设多列链接和 <code>copyright</code> 文案。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十主题与样式\">十、主题与样式<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E5%8D%81%E4%B8%BB%E9%A2%98%E4%B8%8E%E6%A0%B7%E5%BC%8F\" class=\"hash-link\" aria-label=\"十、主题与样式的直接链接\" title=\"十、主题与样式的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"101-全局样式\">10.1 全局样式<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#101-%E5%85%A8%E5%B1%80%E6%A0%B7%E5%BC%8F\" class=\"hash-link\" aria-label=\"10.1 全局样式的直接链接\" title=\"10.1 全局样式的直接链接\">​</a></h3>\n<p>在 <code>src/css/custom.css</code> 中写全局 CSS，会作用于全站。例如修改主题色、字体等：</p>\n<div class=\"language-css codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-css codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token selector pseudo-class\" style=\"color:hsl(119, 34%, 47%)\">:root</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#2e8555</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-font-family-base</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Your Font'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> system-ui</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> sans-serif</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"102-深色模式\">10.2 深色模式<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#102-%E6%B7%B1%E8%89%B2%E6%A8%A1%E5%BC%8F\" class=\"hash-link\" aria-label=\"10.2 深色模式的直接链接\" title=\"10.2 深色模式的直接链接\">​</a></h3>\n<p>默认支持跟随系统或手动切换。在 <code>themeConfig.colorMode</code> 中可配置：</p>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">colorMode</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  defaultMode</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'light'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  respectPrefersColorScheme</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"103-自定义组件样式\">10.3 自定义组件样式<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#103-%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6%E6%A0%B7%E5%BC%8F\" class=\"hash-link\" aria-label=\"10.3 自定义组件样式的直接链接\" title=\"10.3 自定义组件样式的直接链接\">​</a></h3>\n<ul>\n<li>给某页或某组件包一层带 class 的 div，在 <code>custom.css</code> 中用该类名写样式</li>\n<li>或使用 <strong>Swizzle</strong> 复制主题组件到项目中再改：<code>npm run swizzle @docusaurus/theme-classic NavbarItem --eject</code>（按需使用）</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十一配置文件docusaurusconfig\">十一、配置文件（docusaurus.config）<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E5%8D%81%E4%B8%80%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6docusaurusconfig\" class=\"hash-link\" aria-label=\"十一、配置文件（docusaurus.config）的直接链接\" title=\"十一、配置文件（docusaurus.config）的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"111-核心字段\">11.1 核心字段<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#111-%E6%A0%B8%E5%BF%83%E5%AD%97%E6%AE%B5\" class=\"hash-link\" aria-label=\"11.1 核心字段的直接链接\" title=\"11.1 核心字段的直接链接\">​</a></h3>\n<table><thead><tr><th>字段</th><th>说明</th></tr></thead><tbody><tr><td><code>title</code></td><td>站点标题</td></tr><tr><td><code>url</code></td><td>站点最终访问的根 URL（部署后要改）</td></tr><tr><td><code>baseUrl</code></td><td>子路径，如 GitHub Pages 用 <code>'/projectName/'</code></td></tr><tr><td><code>favicon</code></td><td>favicon 路径</td></tr><tr><td><code>organizationName</code> / <code>projectName</code></td><td>常用于 GitHub 部署与编辑链接</td></tr><tr><td><code>presets</code></td><td>预设（如 classic），以及 docs/blog 等开关与选项</td></tr><tr><td><code>themeConfig</code></td><td>导航栏、页脚、颜色、Algolia 搜索等</td></tr><tr><td><code>plugins</code></td><td>插件列表</td></tr><tr><td><code>i18n</code></td><td>多语言配置</td></tr></tbody></table>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"112-多语言i18n\">11.2 多语言（i18n）<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#112-%E5%A4%9A%E8%AF%AD%E8%A8%80i18n\" class=\"hash-link\" aria-label=\"11.2 多语言（i18n）的直接链接\" title=\"11.2 多语言（i18n）的直接链接\">​</a></h3>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">i18n</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  defaultLocale</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'zh-Hans'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  locales</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'zh-Hans'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'en'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>然后在项目根执行：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run write-translations</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>会在 <code>i18n/</code> 下生成待翻译的 JSON，翻译后构建时会生成各语言版本。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"113-文档版本versioning\">11.3 文档版本（Versioning）<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#113-%E6%96%87%E6%A1%A3%E7%89%88%E6%9C%ACversioning\" class=\"hash-link\" aria-label=\"11.3 文档版本（Versioning）的直接链接\" title=\"11.3 文档版本（Versioning）的直接链接\">​</a></h3>\n<p>适用于「多个大版本文档并存」的场景。首次为当前内容打一个版本：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run docusaurus docs:version </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1.0</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>会生成 <code>versioned_docs/version-1.0/</code> 等，并在导航栏出现版本选择器。新文档继续在 <code>docs/</code> 写，代表「当前/下一版」。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十二构建与部署\">十二、构建与部署<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E5%8D%81%E4%BA%8C%E6%9E%84%E5%BB%BA%E4%B8%8E%E9%83%A8%E7%BD%B2\" class=\"hash-link\" aria-label=\"十二、构建与部署的直接链接\" title=\"十二、构建与部署的直接链接\">​</a></h2>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"121-本地构建\">12.1 本地构建<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#121-%E6%9C%AC%E5%9C%B0%E6%9E%84%E5%BB%BA\" class=\"hash-link\" aria-label=\"12.1 本地构建的直接链接\" title=\"12.1 本地构建的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run build</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>产物在 <code>build/</code> 目录，为静态 HTML/CSS/JS。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"122-本地预览构建结果\">12.2 本地预览构建结果<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#122-%E6%9C%AC%E5%9C%B0%E9%A2%84%E8%A7%88%E6%9E%84%E5%BB%BA%E7%BB%93%E6%9E%9C\" class=\"hash-link\" aria-label=\"12.2 本地预览构建结果的直接链接\" title=\"12.2 本地预览构建结果的直接链接\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run serve</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>会以生产模式打开 <code>build/</code> 内容，用于检查部署效果。</p>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"123-部署到-github-pages\">12.3 部署到 GitHub Pages<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#123-%E9%83%A8%E7%BD%B2%E5%88%B0-github-pages\" class=\"hash-link\" aria-label=\"12.3 部署到 GitHub Pages的直接链接\" title=\"12.3 部署到 GitHub Pages的直接链接\">​</a></h3>\n<ul>\n<li>安装 gh-pages：<code>npm install --save-dev gh-pages</code></li>\n<li>在 <code>package.json</code> 中加：</li>\n</ul>\n<div class=\"language-json codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-json codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"scripts\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"deploy\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"docusaurus deploy\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<ul>\n<li>在 <code>docusaurus.config.ts</code> 中设置：</li>\n</ul>\n<div class=\"language-ts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-ts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">url</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'https://你的用户名.github.io'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">baseUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'/仓库名/'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">projectName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'仓库名'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">organizationName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'你的用户名'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<ul>\n<li>执行：<code>npm run deploy</code>（会构建并推送到 <code>gh-pages</code> 分支）</li>\n</ul>\n<h3 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"124-部署到其他平台\">12.4 部署到其他平台<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#124-%E9%83%A8%E7%BD%B2%E5%88%B0%E5%85%B6%E4%BB%96%E5%B9%B3%E5%8F%B0\" class=\"hash-link\" aria-label=\"12.4 部署到其他平台的直接链接\" title=\"12.4 部署到其他平台的直接链接\">​</a></h3>\n<p>只要能把 <code>build/</code> 目录的内容放到任意静态托管即可（Vercel、Netlify、自有 Nginx 等）。构建命令为 <code>npm run build</code>，站点根目录指向 <code>build</code>。</p>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十三常用命令速查\">十三、常用命令速查<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E5%8D%81%E4%B8%89%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E9%80%9F%E6%9F%A5\" class=\"hash-link\" aria-label=\"十三、常用命令速查的直接链接\" title=\"十三、常用命令速查的直接链接\">​</a></h2>\n<table><thead><tr><th>命令</th><th>说明</th></tr></thead><tbody><tr><td><code>npm run start</code></td><td>启动开发服务器（可加 <code>--host 0.0.0.0</code>）</td></tr><tr><td><code>npm run build</code></td><td>生产环境构建</td></tr><tr><td><code>npm run serve</code></td><td>本地预览构建结果</td></tr><tr><td><code>npm run deploy</code></td><td>构建并部署（如 GitHub Pages）</td></tr><tr><td><code>npm run clear</code></td><td>清除缓存与构建产物</td></tr><tr><td><code>npm run swizzle &lt;组件&gt;</code></td><td>将主题组件「拷贝」到项目以便覆盖</td></tr><tr><td><code>npm run write-translations</code></td><td>生成多语言翻译文件</td></tr><tr><td><code>npm run docusaurus docs:version &lt;版本号&gt;</code></td><td>为文档打版本</td></tr></tbody></table>\n<hr>\n<h2 class=\"anchor anchorWithStickyNavbar_i3DH\" id=\"十四学习路径小结\">十四、学习路径小结<a href=\"https://xn--qbyt9x.me/blog/docusaurus-tutorial#%E5%8D%81%E5%9B%9B%E5%AD%A6%E4%B9%A0%E8%B7%AF%E5%BE%84%E5%B0%8F%E7%BB%93\" class=\"hash-link\" aria-label=\"十四、学习路径小结的直接链接\" title=\"十四、学习路径小结的直接链接\">​</a></h2>\n<ol>\n<li><strong>入门</strong>：创建项目 → 改 <code>docs/intro.md</code> → 看侧边栏与热更新</li>\n<li><strong>文档</strong>：在 <code>docs/</code> 新增文档、用 Front Matter 和 <code>_category_.json</code> 组织侧边栏</li>\n<li><strong>内容</strong>：掌握 MDX、代码块、Admonition、自定义组件</li>\n<li><strong>博客</strong>：在 <code>blog/</code> 写文章，配置 authors/tags</li>\n<li><strong>页面</strong>：在 <code>src/pages/</code> 做关于页、落地页等</li>\n<li><strong>外观</strong>：改 <code>custom.css</code>、navbar、footer</li>\n<li><strong>配置</strong>：熟悉 <code>docusaurus.config.ts</code> 与 <code>sidebars.ts</code></li>\n<li><strong>进阶</strong>：i18n、版本、Swizzle、自定义插件</li>\n</ol>\n<p>遇到问题可查阅 <a href=\"https://docusaurus.io/zh-CN/docs\" target=\"_blank\" rel=\"noopener noreferrer\">Docusaurus 官方文档</a>。</p>",
            "url": "https://老王.me/blog/docusaurus-tutorial",
            "title": "Docusaurus 完整教程（新手向）",
            "summary": "由浅入深学习 Docusaurus，覆盖安装、文档、侧边栏、MDX、博客、页面、主题、配置与部署等主要知识点。",
            "date_modified": "2026-03-19T09:16:45.000Z",
            "tags": []
        }
    ]
}