<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>老王</title>
        <link>https://老王.me/blog</link>
        <description>feedId:41215011978385457+userId:41840354283324416</description>
        <lastBuildDate>Thu, 19 Mar 2026 15:11:56 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-CN</language>
        <copyright>Copyright © 2026 老王 Built with Docusaurus.&lt;p&gt;&lt;a href="http://beian.miit.gov.cn/" class="footer_lin"&gt;&lt;/a&gt;&lt;/p&gt;</copyright>
        <item>
            <title><![CDATA[TypeScript 完整教程（新手向）]]></title>
            <link>https://老王.me/blog/ts-tutorial</link>
            <guid>https://老王.me/blog/ts-tutorial</guid>
            <pubDate>Thu, 19 Mar 2026 15:11:56 GMT</pubDate>
            <description><![CDATA[由浅入深学习 TypeScript，覆盖类型系统、接口与泛型、工程化（tsconfig/构建）、与 Node.js 结合开发 API 等主要知识点。]]></description>
            <content:encoded><![CDATA[<p>本教程面向零基础或刚接触 TypeScript 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>
<hr>
<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>
<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>
<p>TypeScript 是 JavaScript 的超集，核心是为代码增加 <strong>静态类型</strong>。它能在你运行之前就发现很多类型错误，从而提升代码可靠性与可维护性。</p>
<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>
<ul>
<li>提高开发时的提示与可发现性（IDE 体验更好）</li>
<li>更早暴露类型相关 bug</li>
<li>更易重构和维护大型工程</li>
</ul>
<hr>
<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>
<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>
<p>在项目目录中初始化：</p>
<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>
<p>安装 TypeScript：</p>
<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>
<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>
<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>
<p><code>tsconfig.json</code> 用于配置编译选项（如 <code>target</code>、<code>module</code>、是否开启严格模式等）。</p>
<hr>
<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>
<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>
<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>
<p>其中：</p>
<ul>
<li><code>any</code>：不做类型约束（慎用）</li>
<li><code>unknown</code>：未知类型，使用前需要判断</li>
</ul>
<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>
<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>
<hr>
<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>
<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>
<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>
<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>
<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>
<p>它们都能描述对象结构，实际项目中可以按团队习惯选择使用。</p>
<hr>
<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>
<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>
<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>
<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>
<p>常见工具类型：</p>
<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>
<hr>
<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>
<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>
<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>
<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>
<p><code>src/user.ts</code>：</p>
<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>
<p><code>src/main.ts</code>：</p>
<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>
<hr>
<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>
<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>
<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>
<p>常用的方式是在 <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 punctuation" style="color:hsl(119, 34%, 47%)">{</span><span 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>
<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>
<p><code>tsconfig.json</code> 中常见选项：</p>
<ul>
<li><code>strict</code>：开启一组严格检查</li>
<li><code>noImplicitAny</code>：禁止隐式 <code>any</code></li>
</ul>
<p>新手建议不要一口气全开，但可以从最基础的开始。</p>
<hr>
<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>
<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>
<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>
<p>创建 <code>src/server.ts</code>：</p>
<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>
<p>启动（开发模式）：</p>
<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>
<hr>
<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>
<p>工程化不是“越多越好”，但至少应做到：</p>
<ul>
<li>统一格式（Prettier）</li>
<li>基于类型的检查与规则（ESLint + TypeScript）</li>
</ul>
<p>你可以先从 <code>prettier</code> 开始，后续再加 ESLint。</p>
<hr>
<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>
<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>
<p>常用方案：</p>
<ul>
<li>单元测试：Jest / Vitest</li>
<li>集成测试：supertest（Express）</li>
</ul>
<p>这里建议你先跑通：</p>
<ol>
<li>把业务逻辑从路由中抽离成函数</li>
<li>对函数进行单测</li>
</ol>
<hr>
<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>
<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>
<ul>
<li>尽量使用明确的类型（至少在边界：入参出参）</li>
<li>使用泛型提升复用</li>
<li>开启 <code>strict</code>（或逐步开启相关严格选项）</li>
<li>把业务逻辑拆分成可测试的模块</li>
</ul>
<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>
<ul>
<li>TypeScript 通过类型系统增强可靠性</li>
<li>接口、类型别名、联合类型与泛型是核心能力</li>
<li>tsconfig 决定编译策略</li>
<li>与 Node.js 结合可直接构建 API（Express 示例）</li>
</ul>
<hr>
<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>
<ol>
<li>跑通 <code>tsc</code> 编译流程，理解输出与模块形式</li>
<li>掌握基础类型、联合类型与类型收窄</li>
<li>学会接口、泛型与常见工具类型</li>
<li>结合 Express 写一个最小 API</li>
<li>从抽离业务逻辑开始加测试，逐步形成工程习惯</li>
</ol>
<p>遇到问题可查阅 <a href="https://www.typescriptlang.org/docs/handbook/intro.html" target="_blank" rel="noopener noreferrer">TypeScript 官方文档</a>。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Next.js 完整教程（新手向）]]></title>
            <link>https://老王.me/blog/nextjs-tutorial</link>
            <guid>https://老王.me/blog/nextjs-tutorial</guid>
            <pubDate>Thu, 19 Mar 2026 15:11:56 GMT</pubDate>
            <description><![CDATA[由浅入深学习 Next.js，覆盖 App Router、路由、数据获取、组件与样式、Route Handler、部署与常见问题等主要知识点。]]></description>
            <content:encoded><![CDATA[<p>本教程面向零基础或刚接触 Next.js 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>
<hr>
<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>
<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>
<p>Next.js 是一个基于 React 的 Web 框架，提供了路由、渲染与构建能力，让你更容易构建：</p>
<ul>
<li>SSR / SSG / 混合渲染应用</li>
<li>全栈 Web（配合 API / Route Handler）</li>
<li>类型友好的工程化开发体验</li>
</ul>
<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>
<ul>
<li>个人博客 / 技术文章站</li>
<li>产品官网与落地页</li>
<li>带用户登录、后台管理的 Web 应用（配合你选择的认证方案）</li>
<li>API 与前后端一体化项目</li>
</ul>
<hr>
<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>
<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>
<ul>
<li><strong>Node.js</strong>：建议使用 18.x 及以上（推荐 20 LTS）</li>
<li>了解基础的 npm/pnpm/yarn 使用</li>
</ul>
<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>
<p>使用官方推荐的脚手架 <code>create-next-app</code>：</p>
<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>
<p>初始化安装完成后进入目录并启动：</p>
<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>
<p>浏览器打开 <code>http://localhost:3000</code> 即可。</p>
<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>
<hr>
<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>
<p>Next.js（新版本）通常使用 <strong>App Router</strong>。常见目录结构如下：</p>
<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>
<p>关键约定：</p>
<ul>
<li><code>app/layout.tsx</code>：全站的根布局（所有页面都会套在里面）</li>
<li><code>app/page.tsx</code>：<code>/</code> 路由对应的页面</li>
<li><code>app/**/page.tsx</code>：<code>app</code> 下的每个文件夹可对应一个路由</li>
</ul>
<hr>
<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>
<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>
<p>创建一个路由 <code>app/about/page.tsx</code>：</p>
<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>
<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>
<p>使用 Next.js 的 <code>Link</code> 进行跳转（推荐）：</p>
<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>
<hr>
<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>
<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>
<p>假设你有 <code>app/components/Hello.module.css</code>：</p>
<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>
<p>然后在组件中使用：</p>
<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>
<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>
<p>通常在 <code>app/globals.css</code> 引入全站样式，并在根布局 <code>layout.tsx</code> 中导入。</p>
<hr>
<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>
<p>在 App Router 下，你常见会遇到几种数据获取方式：</p>
<ol>
<li><strong>Server Components 里直接 fetch</strong>（最常见的新手路径）</li>
<li>使用 <strong>Route Handler</strong> 提供 API，再在客户端请求</li>
<li>需要更复杂缓存策略时，显式配置 Next.js 的缓存行为</li>
</ol>
<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>
<p><code>app/posts/page.tsx</code>：</p>
<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>
<hr>
<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>
<p>在 App Router 中，你可以在 <code>app/api/.../route.ts</code> 里写接口。</p>
<p>例如 <code>app/api/health/route.ts</code>：</p>
<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>
<p>访问：<code>/api/health</code></p>
<p>你也可以扩展为 <code>POST / PUT / DELETE</code> 等方法。</p>
<hr>
<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>
<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>
<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>
<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>
<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>
<hr>
<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>
<p>Next.js 官方在 Vercel 上体验最佳。一般步骤：</p>
<ul>
<li>把项目推到 GitHub</li>
<li>在 Vercel 创建新项目并导入仓库</li>
<li>使用 Vercel 默认构建命令（通常就是 <code>npm run build</code>）</li>
</ul>
<hr>
<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>
<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>
<ul>
<li>为什么我写的页面路由不生效？<!-- -->
<ul>
<li>确认 <code>app</code> 目录下的 <code>page.tsx</code> 是否放对路径（例如 <code>app/about/page.tsx</code> 对应 <code>/about</code>）</li>
</ul>
</li>
<li>为什么数据没有更新？<!-- -->
<ul>
<li>App Router 下 <code>fetch</code> 的缓存策略可能不同；新手阶段可先用 <code>cache: 'no-store'</code></li>
</ul>
</li>
</ul>
<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>
<ul>
<li>用 <code>app/</code> 组织路由：<code>layout.tsx</code> + <code>page.tsx</code></li>
<li>用 <code>Link</code> 做跳转</li>
<li>用 CSS Modules 管理样式</li>
<li>在 Server Components 中 <code>fetch</code> 获取数据</li>
<li>用 <code>app/api/.../route.ts</code> 提供接口</li>
<li>用 <code>npm run build</code> / <code>npm run start</code> 完成构建与预览</li>
</ul>
<hr>
<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>
<ol>
<li>新建 Next.js 项目并跑通 <code>npm run dev</code></li>
<li>写 <code>layout.tsx</code> 和一个 <code>about/page.tsx</code></li>
<li>用 <code>Link</code> 做页面跳转</li>
<li>写一个 <code>fetch</code> 示例页面并观察加载行为</li>
<li>写 <code>app/api/health/route.ts</code> 测试接口</li>
<li>完成 <code>npm run build</code> 与本地 <code>npm run start</code> 预览</li>
</ol>
<p>遇到问题可查阅 <a href="https://nextjs.org/docs" target="_blank" rel="noopener noreferrer">Next.js 官方文档</a>。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[NestJS 完整教程（新手向）]]></title>
            <link>https://老王.me/blog/nestjs-tutorial</link>
            <guid>https://老王.me/blog/nestjs-tutorial</guid>
            <pubDate>Thu, 19 Mar 2026 09:16:45 GMT</pubDate>
            <description><![CDATA[由浅入深学习 NestJS，覆盖控制器、服务、模块、依赖注入、管道、守卫、拦截器、数据库、认证与部署等主要知识点。]]></description>
            <content:encoded><![CDATA[<p>本教程面向零基础或刚接触 NestJS 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>
<hr>
<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>
<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>
<p>NestJS 是一个基于 <strong>Node.js</strong> 的 <strong>服务端框架</strong>，使用 <strong>TypeScript</strong> 编写，架构风格借鉴了 Angular。特点包括：</p>
<ul>
<li><strong>分层清晰</strong>：控制器、服务、模块等概念明确，适合中大型项目</li>
<li><strong>依赖注入（DI）</strong>：内置 IoC 容器，便于测试与解耦</li>
<li><strong>TypeScript 优先</strong>：类型安全、装饰器驱动</li>
<li><strong>可扩展</strong>：支持 REST、GraphQL、WebSocket、微服务等</li>
<li><strong>生态丰富</strong>：与 TypeORM、Prisma、Passport、class-validator 等无缝集成</li>
</ul>
<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>
<ul>
<li>RESTful API / BFF（Backend for Frontend）</li>
<li>GraphQL 服务</li>
<li>微服务（配合 Kafka、RabbitMQ 等）</li>
<li>实时应用（WebSocket、SSE）</li>
<li>需要严格架构与可维护性的 Node 后端</li>
</ul>
<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>
<ul>
<li><strong>JavaScript/TypeScript</strong> 基础</li>
<li><strong>Node.js</strong> 与 npm 基本使用</li>
<li>了解 <strong>HTTP</strong>、<strong>REST</strong> 概念更佳</li>
</ul>
<hr>
<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>
<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>
<ul>
<li><strong>Node.js</strong>：18.x 及以上（建议 20 LTS）</li>
<li><strong>包管理器</strong>：npm / yarn / pnpm</li>
</ul>
<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>
<p>安装 Nest CLI（可选，也可用 <code>npx</code> 不全局安装）：</p>
<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>
<p>或直接用 npx：</p>
<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>
<p>按提示选择包管理器（npm / yarn / pnpm），完成后进入项目并启动：</p>
<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>
<p>浏览器访问 <strong><a href="http://localhost:3000/" target="_blank" rel="noopener noreferrer">http://localhost:3000</a></strong> 应看到 <code>Hello World!</code>。</p>
<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>
<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>
<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>
<hr>
<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>
<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>
<ul>
<li><strong>main.ts</strong>：创建 <code>NestFactory.create(AppModule)</code>、监听端口、可配置全局管道/前缀等</li>
<li><strong>app.module.ts</strong>：根模块，通过 <code>imports</code> 聚合其他模块</li>
<li><strong>app.controller.ts</strong> / <strong>app.service.ts</strong>：根控制器与根服务，演示最基础的请求处理与业务逻辑</li>
</ul>
<p>后续会按功能拆成多个模块（如 <code>users</code>、<code>posts</code>），每个模块可有自己的 <code>*.module.ts</code>、<code>*.controller.ts</code>、<code>*.service.ts</code>。</p>
<hr>
<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>
<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>
<p>模块是组织代码的单元，把<strong>控制器、服务、其他模块</strong>组织在一起。</p>
<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>
<ul>
<li><strong>imports</strong>：引入其他模块（使用其 exports）</li>
<li><strong>controllers</strong>：该模块下的控制器（处理 HTTP 等）</li>
<li><strong>providers</strong>：该模块下的可注入服务</li>
<li><strong>exports</strong>：把 providers 暴露给其他模块</li>
</ul>
<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>
<p>控制器负责<strong>处理入站请求</strong>并返回响应，对应路由与 HTTP 方法。</p>
<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>
<ul>
<li><strong>@Controller('prefix')</strong>：该控制器下所有路由共用的前缀，如 <code>@Controller('users')</code> 则路由为 <code>/users/...</code></li>
<li><strong>@Get()</strong>、<strong>@Post()</strong>、<strong>@Put()</strong>、<strong>@Patch()</strong>、<strong>@Delete()</strong>：对应 HTTP 方法</li>
<li><strong>constructor</strong> 中注入 <strong>AppService</strong>：由 Nest 的依赖注入提供实例</li>
</ul>
<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>
<p>服务承载<strong>业务逻辑</strong>，被控制器注入并调用，避免在控制器里写复杂逻辑。</p>
<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>
<ul>
<li><strong>@Injectable()</strong>：表示该类可由 Nest 的 DI 容器管理，并注入到其他类中</li>
</ul>
<p><strong>关系小结</strong>：请求 → 控制器（路由）→ 调用服务（业务）→ 返回响应。</p>
<hr>
<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>
<p>Nest 内置 <strong>IoC 容器</strong>：你只声明「需要什么类」，容器负责创建实例并注入。</p>
<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>
<ul>
<li><strong>Provider</strong>：在某个模块的 <code>providers</code> 里声明（如 <code>AppService</code>）</li>
<li><strong>注入</strong>：在控制器或其它服务的 <code>constructor</code> 中写上类型，Nest 会注入该模块或已导入模块的 <code>exports</code> 中的对应实例</li>
<li><strong>作用域</strong>：默认单例；可按需使用 <code>Scope.REQUEST</code> 等实现请求级实例</li>
</ul>
<hr>
<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>
<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>
<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>
<p>常用参数装饰器：</p>
<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>
<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>
<p>在 <code>main.ts</code> 中可为所有路由加前缀：</p>
<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>
<hr>
<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>
<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>
<ul>
<li>定义请求体的<strong>形状</strong>，便于类型提示和文档</li>
<li>配合 <strong>class-validator</strong> 做<strong>自动校验</strong>，非法请求在进入控制器前被拦截</li>
</ul>
<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>
<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>
<p>在 <code>main.ts</code> 中启用全局验证管道：</p>
<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>
<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>
<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>
<p>控制器中直接使用即可，校验失败时 Nest 自动返回 400 与错误信息：</p>
<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>
<hr>
<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>
<p>管道用于<strong>转换或校验</strong>输入数据，在到达控制器方法之前执行。</p>
<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>
<ul>
<li><strong>ValidationPipe</strong>：上面已用，配合 class-validator</li>
<li><strong>ParseIntPipe</strong>：将参数转为整数，否则 400</li>
</ul>
<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>
<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>
<p>实现 <code>PipeTransform</code> 接口即可：</p>
<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>
<p>在参数或控制器上使用：<code>@Query('active', ParseBoolPipe) active: boolean</code>。</p>
<hr>
<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>
<p>守卫决定<strong>是否允许请求继续</strong>，常用于<strong>权限、角色</strong>校验。</p>
<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>
<ul>
<li>控制器级：<code>@UseGuards(RolesGuard)</code></li>
<li>方法级：同上</li>
<li>全局：<code>app.useGlobalGuards(new RolesGuard())</code></li>
</ul>
<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>
<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>
<p>通过 <strong>Reflector</strong> 读取元数据（如自定义装饰器 <code>@Roles('admin')</code>），再根据 <code>user</code> 判断。若返回 <code>false</code>，Nest 默认返回 403。</p>
<hr>
<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>
<p>拦截器可在<strong>请求前/后</strong>统一处理逻辑，如日志、超时、响应格式封装等。</p>
<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>
<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>
<p>在 <code>main.ts</code> 中全局注册：<code>app.useGlobalInterceptors(new TransformInterceptor());</code>，则所有控制器返回的数据会被包成 <code>{ data, timestamp }</code>。</p>
<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>
<ul>
<li>统一包装 <code>{ code, data, message }</code></li>
<li>日志、耗时统计</li>
<li>超时控制（<code>timeout</code> RxJS 操作符）</li>
</ul>
<hr>
<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>
<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>
<p>在服务或控制器中直接抛出，Nest 会转为对应状态码的 JSON：</p>
<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>
<p>常用：<code>BadRequestException</code>(400)、<code>UnauthorizedException</code>(401)、<code>ForbiddenException</code>(403)、<code>NotFoundException</code>(404) 等。</p>
<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>
<p>若希望<strong>统一格式</strong>或对特定异常做特殊处理，可写异常过滤器：</p>
<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>
<p>使用：<code>@UseFilters(HttpExceptionFilter)</code> 或 <code>app.useGlobalFilters(new HttpExceptionFilter())</code>。</p>
<hr>
<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>
<p>中间件在<strong>路由处理器之前</strong>执行，可做日志、解析、限流等。</p>
<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>
<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>
<p>在模块中挂到指定路由：</p>
<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>
<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>
<p>若无需依赖注入，可写为普通函数，在 <code>consumer.apply(LoggerMiddleware)</code> 处传入即可。</p>
<hr>
<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>
<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>
<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>
<p>根模块中引入：</p>
<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>
<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>
<p>在服务或控制器中注入 <code>ConfigService</code>：</p>
<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>
<p>推荐配合 <code>.env</code> 文件，不要提交敏感信息。</p>
<hr>
<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>
<p>Nest 与 <strong>TypeORM</strong>、<strong>Prisma</strong> 等都能很好集成，这里以 TypeORM 为例说明「模块 + 实体」的用法。</p>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>更多（关系、迁移、事务）请查阅 <a href="https://typeorm.io/" target="_blank" rel="noopener noreferrer">TypeORM 文档</a>。</p>
<hr>
<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>
<p>认证涉及「登录签发 token」和「请求时校验 token」，常用 <strong>Passport + JWT</strong>。</p>
<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>
<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>
<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>
<ul>
<li><strong>登录</strong>：用 <code>LocalStrategy</code> 校验用户名密码，通过后用 <code>JwtService.sign()</code> 签发 token，返回给前端。</li>
<li><strong>受保护路由</strong>：用 <code>JwtStrategy</code> 从 Header 的 Bearer token 中解析出用户信息，挂到 <code>request.user</code>；再用 <strong>Guard</strong> 在需要登录的接口上使用 <code>JwtAuthGuard</code>。</li>
</ul>
<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>
<p>在模块中注册：</p>
<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>
<p>在需要登录的控制器或方法上添加：</p>
<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>
<p>具体实现可参考官方文档 <a href="https://docs.nestjs.com/security/authentication" target="_blank" rel="noopener noreferrer">NestJS 认证</a>。</p>
<hr>
<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>
<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>
<p>使用 Jest，对服务类进行隔离测试，依赖用 mock：</p>
<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>
<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>
<p>对完整 HTTP 请求做测试：</p>
<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>
<p>运行：<code>npm run test</code>（单元）、<code>npm run test:e2e</code>（E2E）。</p>
<hr>
<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>
<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>
<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>
<p>产物在 <code>dist/</code>，为编译后的 JavaScript。</p>
<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>
<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>
<p>会执行 <code>node dist/main</code>（或你配置的入口）。生产环境建议用 <strong>PM2</strong>、<strong>Docker</strong> 或云平台的 Node 运行时，并设置好环境变量（如 <code>NODE_ENV=production</code>、数据库与 JWT 的配置）。</p>
<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>
<ul>
<li>使用 <strong>环境变量</strong> 管理配置，不要写死敏感信息</li>
<li>数据库用 <strong>迁移</strong> 管理表结构，不要依赖 <code>synchronize: true</code></li>
<li>可配合 <strong>Nginx</strong> 做反向代理与静态资源</li>
<li>健康检查可暴露一个 <code>/health</code> 接口供负载均衡使用</li>
</ul>
<hr>
<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>
<ol>
<li><strong>入门</strong>：创建项目 → 理解 Module / Controller / Service → 改根路由看效果</li>
<li><strong>请求</strong>：路由、@Param / @Query / @Body、DTO + ValidationPipe</li>
<li><strong>结构</strong>：按功能拆模块（如 UsersModule）、依赖注入与 exports</li>
<li><strong>增强</strong>：管道、守卫、拦截器、异常过滤器、中间件</li>
<li><strong>数据</strong>：ConfigModule、TypeORM/Prisma、实体与 Repository</li>
<li><strong>安全</strong>：JWT 认证、角色守卫</li>
<li><strong>质量</strong>：单元测试、E2E 测试</li>
<li><strong>上线</strong>：build、环境变量、进程管理、健康检查</li>
</ol>
<p>遇到问题可查阅 <a href="https://docs.nestjs.com/" target="_blank" rel="noopener noreferrer">NestJS 官方文档</a>。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Node.js 完整教程（新手向）]]></title>
            <link>https://老王.me/blog/nodejs-tutorial</link>
            <guid>https://老王.me/blog/nodejs-tutorial</guid>
            <pubDate>Thu, 19 Mar 2026 15:11:56 GMT</pubDate>
            <description><![CDATA[由浅入深学习 Node.js，覆盖环境与 npm、模块系统、异步与事件循环、HTTP 与 Express、日志错误处理、测试与部署等主要知识点。]]></description>
            <content:encoded><![CDATA[<p>本教程面向零基础或刚接触 Node.js 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>
<hr>
<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>
<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>
<p>Node.js 是一个让 JavaScript 在服务器端运行的运行时环境。它解决了浏览器只能运行 JS 的限制，让你可以用 JS 写：</p>
<ul>
<li>HTTP 接口服务</li>
<li>命令行工具</li>
<li>数据处理脚本</li>
</ul>
<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>
<ul>
<li>API 不一样（浏览器有 DOM，Node 有文件系统/网络等）</li>
<li>运行模型不同（Node 是服务器侧环境）</li>
<li>模块系统不同（CommonJS / ESM）</li>
</ul>
<hr>
<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>
<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>
<ul>
<li>建议使用 LTS 版本</li>
<li>可使用 nvm 管理多个版本（可选）</li>
</ul>
<p>确认版本：</p>
<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>
<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>
<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>
<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>
<ul>
<li><code>name</code> / <code>version</code></li>
<li><code>main</code>（入口）</li>
<li><code>scripts</code>（一键执行脚本）</li>
</ul>
<p>例如加入开发脚本：</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 punctuation" style="color:hsl(119, 34%, 47%)">{</span><span 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>
<hr>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<p>建议你在新项目中统一一种模块方式（ESM 更现代），并结合团队约定。</p>
<hr>
<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>
<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>
<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>
<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>
<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>
<hr>
<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>
<p>创建 <code>src/server.js</code>：</p>
<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>
<p>启动：</p>
<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>
<p>访问：<code>http://localhost:3000/health</code></p>
<hr>
<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>
<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>
<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>
<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>
<p>创建 <code>src/app.js</code>：</p>
<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>
<p>启动：</p>
<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>
<hr>
<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>
<p>新手建议先把“接口层”和“数据层”分开。你可以从简单存储开始，例如：</p>
<ul>
<li>内存对象（原型期）</li>
<li>JSON 文件（演示用）</li>
</ul>
<p>等接口逻辑稳定后再替换为数据库（如 PostgreSQL / MySQL）。</p>
<hr>
<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>
<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>
<p>Express 可以通过中间件做统一处理：</p>
<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>
<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>
<ul>
<li>开发期：<code>console.log</code> 够用</li>
<li>生产期：用成熟日志库（如 pino/winston）更可观测</li>
</ul>
<hr>
<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>
<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>
<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>
<p>在 <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 punctuation" style="color:hsl(119, 34%, 47%)">{</span><span 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>
<p>写测试：</p>
<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>
<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>
<ul>
<li>使用断点调试（IDE）</li>
<li>关键函数先写日志，再逐步定位问题</li>
</ul>
<hr>
<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>
<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>
<ul>
<li>静态站点不适用后端部署</li>
<li>后端服务通常使用：<!-- -->
<ul>
<li>进程管理：PM2</li>
<li>容器：Docker</li>
<li>平台：Vercel/Render/Fly.io 等（取决于你的项目形态）</li>
</ul>
</li>
</ul>
<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>
<ul>
<li>Node：用 JS 写后端服务</li>
<li>npm：管理依赖与脚本</li>
<li>模块：CommonJS / ESM 二选一并统一</li>
<li>异步：Promise 与 async/await</li>
<li>API：原生 http 与 Express 入门</li>
<li>质量：Jest 测试与统一错误处理</li>
</ul>
<hr>
<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>
<ol>
<li>安装 Node 并完成 npm 项目初始化</li>
<li>理解模块系统（require/import）</li>
<li>写几个 async/await 的函数并练习错误捕获</li>
<li>用原生 http 实现 <code>/health</code></li>
<li>用 Express 做一个最小 API（health + echo）</li>
<li>加上至少 1-2 个 Jest 单测，再考虑部署</li>
</ol>
<p>遇到问题可查阅 <a href="https://nodejs.org/en/docs/" target="_blank" rel="noopener noreferrer">Node.js 官方文档</a> 与社区示例。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Python 完整教程（新手向）]]></title>
            <link>https://老王.me/blog/python-tutorial</link>
            <guid>https://老王.me/blog/python-tutorial</guid>
            <pubDate>Thu, 19 Mar 2026 15:11:56 GMT</pubDate>
            <description><![CDATA[由浅入深学习 Python，覆盖语法基础、类型标注、异常处理、第三方库、Web 入门、测试、调试与部署等主要知识点。]]></description>
            <content:encoded><![CDATA[<p>本教程面向零基础或刚接触 Python 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>
<hr>
<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>
<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>
<p>Python 是一种 <strong>解释型</strong>、<strong>面向对象</strong>且以 <strong>可读性强</strong> 著称的编程语言。它的生态非常成熟，常见用途包括：</p>
<ul>
<li>脚本自动化（写小工具、处理文件、跑任务）</li>
<li>数据分析与数据工程（Pandas、NumPy 等）</li>
<li>Web 后端与接口服务（FastAPI、Flask 等）</li>
<li>AI / 机器学习（生态强，社区资源多）</li>
</ul>
<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>
<ul>
<li>想用更少代码快速完成一个功能</li>
<li>想做 API、脚本、爬虫或数据处理</li>
<li>希望语言本身对新手友好，并且拥有大量开源库</li>
</ul>
<hr>
<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>
<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>
<ul>
<li>到官方站下载安装包（推荐 3.x 最新稳定版）</li>
<li>如果你在 Linux/WSL 下，也可以使用系统包管理器或版本管理工具（如 pyenv）</li>
</ul>
<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>
<p>避免把依赖装到全局 Python，造成版本冲突：</p>
<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>
<p>激活虚拟环境：</p>
<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>
<p>升级 pip 并安装依赖：</p>
<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>
<blockquote>
<p>提示：创建虚拟环境可以让每个项目的依赖互相独立，更容易复现和部署。</p>
</blockquote>
<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>
<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>
<p>也可以直接用模块方式运行：</p>
<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>
<hr>
<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>
<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>
<p>Python 不需要写类型声明：</p>
<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>
<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>
<ul>
<li><code>int</code>：整数</li>
<li><code>float</code>：浮点数</li>
<li><code>str</code>：字符串</li>
<li><code>bool</code>：布尔值</li>
<li><code>list</code>：列表（可变）</li>
<li><code>tuple</code>：元组（不可变，推荐当作“固定结构”使用）</li>
<li><code>dict</code>：字典（键值对）</li>
<li><code>set</code>：集合（去重）</li>
</ul>
<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>
<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>
<hr>
<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>
<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>
<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>
<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>
<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>
<p>while 循环：</p>
<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>
<hr>
<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>
<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>
<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>
<p>其中：</p>
<ul>
<li><code>a: int</code> / <code>b: int</code> 是类型标注（运行时不强制）</li>
<li><code>-&gt; int</code> 表示返回类型</li>
</ul>
<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>
<p>假设有 <code>utils.py</code>：</p>
<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>
<p>在 <code>main.py</code>：</p>
<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>
<hr>
<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>
<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>
<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>
<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>
<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>
<p>也可以在捕获后重新抛出：</p>
<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>
<hr>
<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>
<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>
<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>
<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>
<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>
<hr>
<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>
<p>当项目变大时，类型标注可以提升可维护性。一个常见结构：</p>
<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>
<p>类型检查工具常见包括 <code>mypy</code>（可按需启用）。</p>
<hr>
<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>
<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>
<p>安装依赖：</p>
<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>
<p>生成依赖清单：</p>
<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>
<p>在新环境安装：</p>
<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>
<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>
<ul>
<li><code>requests</code>：发 HTTP 请求</li>
<li><code>pydantic</code>：数据校验与结构化（FastAPI 经常用）</li>
<li><code>httpx</code>：现代 HTTP 客户端（异步友好）</li>
</ul>
<hr>
<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>
<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>
<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>
<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>
<p>创建 <code>main.py</code>：</p>
<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>
<p>启动服务：</p>
<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>
<p>访问：<code>http://localhost:8000/health</code></p>
<hr>
<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>
<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>
<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>
<p>写测试示例：<code>tests/test_main.py</code></p>
<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>
<p>运行：</p>
<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>
<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>
<ul>
<li>使用 <code>print()</code> 快速定位问题</li>
<li>必要时使用 <code>logging</code> 代替 <code>print</code>（更可控）</li>
<li>Python 可直接用 <code>breakpoint()</code> 进入调试</li>
</ul>
<hr>
<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>
<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>
<ul>
<li>使用虚拟环境或容器打包依赖</li>
<li>保证环境变量（如数据库连接串）在部署平台配置</li>
<li>生产环境通常用 <code>uvicorn</code> + 反向代理（如 Nginx）</li>
</ul>
<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>
<ul>
<li>Python 基础：语法、数据类型、控制流</li>
<li>工程能力：虚拟环境、requirements、项目结构</li>
<li>Web：FastAPI + uvicorn 快速起服务</li>
<li>质量：pytest 做测试</li>
</ul>
<hr>
<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>
<ol>
<li>学会变量、函数、循环与常见数据结构</li>
<li>逐步引入类型标注，让代码更易维护</li>
<li>熟悉虚拟环境与依赖管理（requirements）</li>
<li>做一个简单 Web 服务（FastAPI）</li>
<li>写至少几条测试（pytest），再逐步扩展项目</li>
</ol>
<p>遇到问题可查阅 <a href="https://docs.python.org/zh-cn/" target="_blank" rel="noopener noreferrer">Python 官方文档</a> 与社区示例。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Go 完整教程（新手向）]]></title>
            <link>https://老王.me/blog/go-tutorial</link>
            <guid>https://老王.me/blog/go-tutorial</guid>
            <pubDate>Thu, 19 Mar 2026 15:11:56 GMT</pubDate>
            <description><![CDATA[由浅入深学习 Go，覆盖基础语法、包与模块、结构体与接口、错误处理、并发（goroutine/channel）、HTTP 服务、测试与部署等主要知识点。]]></description>
            <content:encoded><![CDATA[<p>本教程面向零基础或刚接触 Go 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>
<hr>
<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>
<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>
<p>Go（又称 Golang）是一种由 Google 主导开发的编程语言，特点包括：</p>
<ul>
<li>语法简洁，学习成本相对低</li>
<li>并发模型原生支持（goroutine + channel）</li>
<li>编译为本地二进制，部署方便</li>
</ul>
<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>
<ul>
<li>高性能网络服务（HTTP/RPC）</li>
<li>需要并发处理的场景</li>
<li>云原生、工具类程序</li>
</ul>
<hr>
<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>
<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>
<ul>
<li>建议安装最新稳定版</li>
<li>确认版本：</li>
</ul>
<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>
<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>
<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>
<p>Go 的依赖管理通常基于 <code>go.mod</code>。</p>
<hr>
<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>
<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>
<p>创建 <code>main.go</code>：</p>
<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">	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 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>
<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>
<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>
<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>
<ul>
<li><code>int</code> / <code>int64</code></li>
<li><code>string</code></li>
<li><code>bool</code></li>
<li><code>float64</code></li>
</ul>
<hr>
<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>
<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>
<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">	</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>
<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>
<p>Go 用目录划分包，例如：</p>
<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>
<p><code>utils/math.go</code>：</p>
<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">	</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>
<p>在 <code>main.go</code> 中使用：</p>
<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>
<hr>
<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>
<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>
<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">	Name </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">	Age  </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>
<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>
<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">	</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>
<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>
<p>接口关注“行为”，而不是具体类型：</p>
<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">	</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">	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">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>
<hr>
<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>
<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>
<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">	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 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>
<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>
<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">	ch </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>
<hr>
<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>
<p>Go 的错误处理通常是显式返回 <code>error</code>：</p>
<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">	</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">		</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">	</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">}</span><span 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%)">"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>
<p>调用方：</p>
<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">	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 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">	</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>
<hr>
<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>
<p>创建 <code>server/main.go</code>：</p>
<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">	</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">	</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">	http</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">		w</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">		</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">	</span><span 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">	http</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>
<p>运行：</p>
<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>
<p>访问：<code>http://localhost:3000/health</code></p>
<hr>
<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>
<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>
<p>在 <code>utils/math_test.go</code>：</p>
<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">	got </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">	</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</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">	</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">}</span><span 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>
<p>运行测试：</p>
<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>
<hr>
<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>
<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>
<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>
<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>
<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>
<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>
<ul>
<li>基础语法：变量、函数、结构体</li>
<li>工程结构：包与 modules（<code>go.mod</code>）</li>
<li>设计能力：接口驱动抽象</li>
<li>并发：goroutine/channel</li>
<li>网络：net/http 做最小服务</li>
<li>质量：<code>go test ./...</code></li>
</ul>
<hr>
<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>
<ol>
<li>跑通 <code>go mod init</code> 并完成一个 <code>main.go</code></li>
<li>学会结构体与方法、接口与多态</li>
<li>写至少一个 goroutine + channel 的例子</li>
<li>做一个 <code>/health</code> 的 HTTP 服务</li>
<li>补上测试：至少 1-2 个 <code>go test</code> 用例</li>
</ol>
<p>遇到问题可查阅 <a href="https://go.dev/doc/" target="_blank" rel="noopener noreferrer">Go 官方文档</a>。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[PHP 完整教程（新手向）]]></title>
            <link>https://老王.me/blog/php-tutorial</link>
            <guid>https://老王.me/blog/php-tutorial</guid>
            <pubDate>Thu, 19 Mar 2026 15:11:56 GMT</pubDate>
            <description><![CDATA[由浅入深学习 PHP，覆盖基础语法、面向对象、Composer 与包管理、PDO 数据访问、简单 Web 服务、测试与部署等主要知识点。]]></description>
            <content:encoded><![CDATA[<p>本教程面向零基础或刚接触 PHP 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>
<hr>
<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>
<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>
<p>PHP 是一种非常成熟的服务端脚本语言，主要用于构建 Web 应用与后端接口。它的生态非常丰富，常见用途包括：</p>
<ul>
<li>动态网页（传统 Web 开发）</li>
<li>后端 API（REST 风格接口）</li>
<li>与数据库交互（MySQL/PostgreSQL 等）</li>
</ul>
<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>
<ul>
<li>需要快速做出可运行的 Web 服务</li>
<li>想学习服务端语言的基本开发模式</li>
<li>对“语法简单 + 生态成熟”有偏好</li>
</ul>
<hr>
<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>
<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>
<ul>
<li>选择适合你系统的安装方式（官方安装包、包管理器或集成环境）</li>
<li>确认版本：</li>
</ul>
<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>
<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>
<p>假设你有一个 <code>public/</code> 目录：</p>
<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>
<p>然后访问：<code>http://localhost:8000</code></p>
<hr>
<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>
<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>
<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>
<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>
<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>
<hr>
<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>
<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>
<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>
<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>
<p>注意函数内部变量的作用域规则：函数内创建的变量默认不会自动暴露到全局作用域中。</p>
<hr>
<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>
<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>
<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>
<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>
<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>
<hr>
<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>
<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>
<ul>
<li>进入官网安装 Composer（或使用系统包管理器）</li>
</ul>
<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>
<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>
<p>然后即可在代码中使用第三方库（具体 API 以库文档为准）。</p>
<hr>
<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>
<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>
<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>
<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>
<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>
<hr>
<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>
<p>你可以用“单入口文件”来做最基础的路由分发（新手学习用）：</p>
<p><code>public/index.php</code>：</p>
<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>
<p>启动后访问：<code>/health</code></p>
<hr>
<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>
<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>
<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>
<p>写一个简单测试：<code>tests/MathTest.php</code></p>
<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>
<p>运行：</p>
<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>
<hr>
<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>
<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>
<ul>
<li>生产环境使用稳定的 Web 服务器（Nginx + PHP-FPM 等）</li>
<li>配置环境变量（数据库连接、密钥等）</li>
<li>使用 Composer 管理依赖并做出可复现的构建</li>
</ul>
<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>
<ul>
<li>语法基础：变量、条件、循环、函数</li>
<li>工程能力：Composer、命名空间</li>
<li>数据：PDO + 预处理</li>
<li>Web：最小路由示例</li>
<li>质量：PHPUnit</li>
</ul>
<hr>
<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>
<ol>
<li>跑通 <code>php -S</code> 并写一个 <code>/health</code> 接口</li>
<li>掌握基础语法与函数（至少 3-5 个练习题）</li>
<li>学会 OOP 并写一个 <code>User</code> 类</li>
<li>使用 Composer 引入一个库，并写一次调用</li>
<li>用 PDO 写一个带预处理的查询示例</li>
<li>最少写 1 个 PHPUnit 测试并运行通过</li>
</ol>
<p>遇到问题可查阅 <a href="https://www.php.net/docs.php" target="_blank" rel="noopener noreferrer">PHP 官方文档</a>。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Docusaurus 完整教程（新手向）]]></title>
            <link>https://老王.me/blog/docusaurus-tutorial</link>
            <guid>https://老王.me/blog/docusaurus-tutorial</guid>
            <pubDate>Thu, 19 Mar 2026 09:16:45 GMT</pubDate>
            <description><![CDATA[由浅入深学习 Docusaurus，覆盖安装、文档、侧边栏、MDX、博客、页面、主题、配置与部署等主要知识点。]]></description>
            <content:encoded><![CDATA[<p>本教程面向零基础或刚接触 Docusaurus 的开发者，按由浅入深的顺序讲解所有主要知识点。建议按章节顺序阅读。</p>
<hr>
<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>
<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>
<p>Docusaurus 是 <strong>Meta（Facebook）开源</strong> 的静态站点生成器，专门为 <strong>文档站、博客、产品主页</strong> 设计。特点包括：</p>
<ul>
<li><strong>基于 React</strong>：可嵌入 React 组件，扩展性强</li>
<li><strong>Markdown / MDX 优先</strong>：用熟悉的 Markdown 写文档，支持 JSX</li>
<li><strong>开箱即用</strong>：侧边栏、导航、搜索、深色模式、多语言等内置</li>
<li><strong>静态站点</strong>：构建后是纯 HTML/CSS/JS，易部署、速度快</li>
</ul>
<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>
<ul>
<li>产品/API 文档</li>
<li>技术博客</li>
<li>开源项目说明站</li>
<li>团队知识库</li>
</ul>
<hr>
<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>
<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>
<ul>
<li><strong>Node.js</strong>：建议 20.0 及以上（LTS 即可）</li>
<li><strong>包管理器</strong>：npm / yarn / pnpm 任选其一</li>
</ul>
<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>
<p>使用官方脚手架（经典模板）：</p>
<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>
<p>按提示选择：</p>
<ul>
<li><strong>模板</strong>：<code>classic</code>（包含文档 + 博客）</li>
<li>是否使用 TypeScript：按需选择</li>
</ul>
<p>进入项目并启动开发服务器：</p>
<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>
<p>在浏览器打开 <strong><a href="http://localhost:3000/" target="_blank" rel="noopener noreferrer">http://localhost:3000</a></strong> 即可看到默认站点。</p>
<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>
<hr>
<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>
<p>理解目录结构有助于后续自定义和排查问题。</p>
<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>
<p>重点目录说明：</p>
<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>
<hr>
<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>
<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>
<p>在 <code>docs/</code> 下新建任意 <code>.md</code> 或 <code>.mdx</code> 文件即可，例如：</p>
<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>
<p>文件顶部可写 <strong>Front Matter</strong>（YAML），用于配置当前页在侧边栏和 SEO 等行为。</p>
<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>
<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>
<p>示例：</p>
<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>
<p>保存后，开发服务器会热更新，文档会出现在侧边栏并可按 <code>sidebar_position</code> 排序。</p>
<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>
<ul>
<li><strong>站内文档</strong>：用 Markdown 链接到相对路径或绝对路径均可。</li>
</ul>
<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>
<ul>
<li><strong>推荐</strong>：使用 Docusaurus 的「文档链接」语法，便于以后改 path 时统一替换：</li>
</ul>
<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>
<hr>
<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>
<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>
<p>在 <code>sidebars.ts</code> 中常见写法：</p>
<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>
<p>表示根据 <code>docs/</code> 的<strong>目录和文件名</strong>自动生成侧边栏，顺序由各文档的 <code>sidebar_position</code> 和文件名共同决定。</p>
<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>
<p>在 <code>docs/</code> 下建子文件夹，并在该文件夹内放一个 <code>_category_.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 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>
<ul>
<li><code>label</code>：侧边栏中显示的分类名</li>
<li><code>position</code>：分类在侧边栏中的顺序</li>
<li><code>link</code>：可选，点分类名时进入「索引页」</li>
</ul>
<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>
<p>若需要完全自定义顺序和结构，可在 <code>sidebars.ts</code> 中手写：</p>
<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>
<ul>
<li>字符串：对应 <code>docs/</code> 下的文档 ID（通常为不含扩展名的路径）</li>
<li><code>type: 'category'</code>：分组，<code>items</code> 为子文档列表</li>
</ul>
<hr>
<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>
<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>
<p>Docusaurus 使用 <strong>MDX</strong>（Markdown + JSX），所以普通 Markdown 都支持，例如：</p>
<ul>
<li>标题、列表、引用、表格</li>
<li><strong>粗体</strong>、<em>斜体</em>、<code>代码</code></li>
<li>链接、图片</li>
<li>代码块（带语法高亮）</li>
</ul>
<p>代码块可指定语言和标题：</p>
<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>
<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>
<p>内置的「提示框」组件，适合做说明、注意、警告等：</p>
<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>
<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>
<p>文件扩展名改为 <code>.mdx</code> 后，可直接写 JSX：</p>
<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>
<p>可引入 <code>src/components/</code> 下的自定义组件，或 Docusaurus 内置组件（如 <code>TOCInline</code>、<code>CodeBlock</code> 等）。</p>
<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>
<p>若保持 <code>.md</code> 扩展名，仍可使用部分「类似 HTML」的写法，但复杂组件建议用 <code>.mdx</code> 并 <code>import</code>。</p>
<hr>
<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>
<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>
<ul>
<li><strong>方式一</strong>：直接在 <code>blog/</code> 下放 <code>YYYY-MM-DD-标题.md</code></li>
<li><strong>方式二</strong>：在 <code>blog/</code> 下建子文件夹，如 <code>blog/2024/03/15-hello.md</code></li>
</ul>
<p>文件名中的日期会用于排序和 URL。</p>
<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>
<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>
<ul>
<li><code>authors</code>：对应 <code>blog/authors.yml</code> 中定义的作者 ID</li>
<li><code>tags</code>：标签，可在 <code>blog/tags.yml</code> 中定义</li>
<li><code>date</code>：发布日期</li>
</ul>
<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>
<p>在 <code>docusaurus.config.ts</code> 的 preset 中可关闭博客或改路径：</p>
<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>
<hr>
<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>
<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>
<p><code>src/pages/</code> 下的文件会变成站点路由：</p>
<ul>
<li><code>src/pages/index.js</code> → <code>/</code></li>
<li><code>src/pages/about.js</code> → <code>/about</code></li>
<li><code>src/pages/help/index.js</code> → <code>/help</code></li>
</ul>
<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>
<p>可以是 React 函数组件，导出默认组件即可：</p>
<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>
<p>使用 <code>&lt;Layout&gt;</code> 可保持与全站一致的导航栏、侧边栏和页脚。</p>
<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>
<p>若想完全自定义首页，可修改或替换 <code>src/pages/index.js</code>，或通过 <code>docusaurus.config.ts</code> 的 <code>plugins</code> 配置首页路由。</p>
<hr>
<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>
<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>
<p>在 <code>docusaurus.config.ts</code> 的 <code>themeConfig.navbar</code> 中配置：</p>
<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>
<ul>
<li><code>docSidebar</code>：指向某个侧边栏（文档入口）</li>
<li><code>to</code>：站内路径</li>
<li><code>href</code>：站外链接</li>
<li><code>docsVersionDropdown</code> / <code>localeDropdown</code>：版本、语言下拉（需先启用对应功能）</li>
</ul>
<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>
<p>在 <code>themeConfig.footer</code> 中配置链接和版权信息，结构与 <code>navbar</code> 类似，可设多列链接和 <code>copyright</code> 文案。</p>
<hr>
<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>
<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>
<p>在 <code>src/css/custom.css</code> 中写全局 CSS，会作用于全站。例如修改主题色、字体等：</p>
<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>
<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>
<p>默认支持跟随系统或手动切换。在 <code>themeConfig.colorMode</code> 中可配置：</p>
<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>
<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>
<ul>
<li>给某页或某组件包一层带 class 的 div，在 <code>custom.css</code> 中用该类名写样式</li>
<li>或使用 <strong>Swizzle</strong> 复制主题组件到项目中再改：<code>npm run swizzle @docusaurus/theme-classic NavbarItem --eject</code>（按需使用）</li>
</ul>
<hr>
<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>
<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>
<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>
<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>
<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>
<p>然后在项目根执行：</p>
<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>
<p>会在 <code>i18n/</code> 下生成待翻译的 JSON，翻译后构建时会生成各语言版本。</p>
<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>
<p>适用于「多个大版本文档并存」的场景。首次为当前内容打一个版本：</p>
<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>
<p>会生成 <code>versioned_docs/version-1.0/</code> 等，并在导航栏出现版本选择器。新文档继续在 <code>docs/</code> 写，代表「当前/下一版」。</p>
<hr>
<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>
<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>
<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>
<p>产物在 <code>build/</code> 目录，为静态 HTML/CSS/JS。</p>
<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>
<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>
<p>会以生产模式打开 <code>build/</code> 内容，用于检查部署效果。</p>
<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>
<ul>
<li>安装 gh-pages：<code>npm install --save-dev gh-pages</code></li>
<li>在 <code>package.json</code> 中加：</li>
</ul>
<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>
<ul>
<li>在 <code>docusaurus.config.ts</code> 中设置：</li>
</ul>
<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>
<ul>
<li>执行：<code>npm run deploy</code>（会构建并推送到 <code>gh-pages</code> 分支）</li>
</ul>
<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>
<p>只要能把 <code>build/</code> 目录的内容放到任意静态托管即可（Vercel、Netlify、自有 Nginx 等）。构建命令为 <code>npm run build</code>，站点根目录指向 <code>build</code>。</p>
<hr>
<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>
<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>
<hr>
<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>
<ol>
<li><strong>入门</strong>：创建项目 → 改 <code>docs/intro.md</code> → 看侧边栏与热更新</li>
<li><strong>文档</strong>：在 <code>docs/</code> 新增文档、用 Front Matter 和 <code>_category_.json</code> 组织侧边栏</li>
<li><strong>内容</strong>：掌握 MDX、代码块、Admonition、自定义组件</li>
<li><strong>博客</strong>：在 <code>blog/</code> 写文章，配置 authors/tags</li>
<li><strong>页面</strong>：在 <code>src/pages/</code> 做关于页、落地页等</li>
<li><strong>外观</strong>：改 <code>custom.css</code>、navbar、footer</li>
<li><strong>配置</strong>：熟悉 <code>docusaurus.config.ts</code> 与 <code>sidebars.ts</code></li>
<li><strong>进阶</strong>：i18n、版本、Swizzle、自定义插件</li>
</ol>
<p>遇到问题可查阅 <a href="https://docusaurus.io/zh-CN/docs" target="_blank" rel="noopener noreferrer">Docusaurus 官方文档</a>。</p>]]></content:encoded>
        </item>
    </channel>
</rss>