Files
rxthinkcmf-wiki/RXThinkCMF_ThinkPhp8_NaiveVue/.vitepress/dist/zh/architecture/request-flow.html
T
2026-10-25 18:52:36 +08:00

400 lines
232 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>请求处理链路 | RXThinkCMF 开发文档</title>
<meta name="description" content="一个典型的 API 请求经过以下阶段:浏览器 → Nginx → CORS 中间件 → Auth 中间件(JWT 认证 + RBAC 鉴权)→ Tenant 中间件 → Demo 中间件 → Log">
<meta name="generator" content="VitePress v1.3.4">
<link rel="preload stylesheet" href="/assets/style.DgIBCYhU.css" as="style">
<script type="module" src="/assets/app.B4uh89vd.js"></script>
<link rel="preload" href="/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
<link rel="modulepreload" href="/assets/chunks/theme.kZCdami4.js">
<link rel="modulepreload" href="/assets/chunks/framework.B-QBKwc1.js">
<link rel="modulepreload" href="/assets/zh_architecture_request-flow.md.D0BsQMGR.lean.js">
<link rel="icon" type="image/svg+xml" href="/logo.svg">
<link rel="icon" type="image/png" href="/logo.png">
<meta property="twitter:card" content="summary_large_image">
<script src="/banner.js" async type="text/javascript"></script>
<script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"light",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
<script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
<script>var _hmt=_hmt||[];(function(){var e=document.createElement("script");e.src="https://hm.baidu.com/hm.js?0c49c7c3cd09fbcaaf60dc5e5c8ff6e7";var c=document.getElementsByTagName("script")[0];c.parentNode.insertBefore(e,c)})();</script>
<link rel="canonical" href="http://docs.thinkphp8.naivevue.rxthink.cn/zh/architecture/request-flow.html">
<meta property="og:type" content="article">
<meta property="og:site_name" content="RXThinkCMF">
<meta property="og:locale" content="zh_CN">
<meta property="og:title" content="请求处理链路">
<meta property="og:description" content="一个典型的 API 请求经过以下阶段:浏览器 → Nginx → CORS 中间件 → Auth 中间件(JWT 认证 + RBAC 鉴权)→ Tenant 中间件 → Demo 中间件 → Log">
<meta property="og:url" content="http://docs.thinkphp8.naivevue.rxthink.cn/zh/architecture/request-flow.html">
<meta property="og:image" content="http://docs.thinkphp8.naivevue.rxthink.cn/logo.png">
<meta property="twitter:title" content="请求处理链路">
<meta property="twitter:description" content="一个典型的 API 请求经过以下阶段:浏览器 → Nginx → CORS 中间件 → Auth 中间件(JWT 认证 + RBAC 鉴权)→ Tenant 中间件 → Demo 中间件 → Log">
<meta property="twitter:url" content="http://docs.thinkphp8.naivevue.rxthink.cn/zh/architecture/request-flow.html">
<meta property="twitter:image" content="http://docs.thinkphp8.naivevue.rxthink.cn/logo.png">
<script type="application/ld+json">[{"@context":"https://schema.org","@type":"TechArticle","headline":"4.2 请求处理链路","description":"一个典型的 API 请求经过以下阶段:浏览器 → Nginx → CORS 中间件 → Auth 中间件(JWT 认证 + RBAC 鉴权)→ Tenant 中间件 → Demo 中间件 → Log","url":"http://docs.thinkphp8.naivevue.rxthink.cn/zh/architecture/request-flow.html","inLanguage":"zh-CN","mainEntityOfPage":{"@type":"WebPage","@id":"http://docs.thinkphp8.naivevue.rxthink.cn/zh/architecture/request-flow.html"},"publisher":{"@type":"Organization","name":"RXThinkCMF","url":"https://www.rxthink.cn","logo":"http://docs.thinkphp8.naivevue.rxthink.cn/logo.png","sameAs":["https://gitee.com/rxthinkcmf/RXThinkCMF_ThinkPhp8_NaiveVue","https://www.rxthink.cn"]},"dateModified":"2026-09-29T10:14:04+08:00"},{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"首页","item":"http://docs.thinkphp8.naivevue.rxthink.cn/"},{"@type":"ListItem","position":2,"name":"4. 架构设计"},{"@type":"ListItem","position":3,"name":"4.2 请求处理链路","item":"http://docs.thinkphp8.naivevue.rxthink.cn/zh/architecture/request-flow.html"}]}]</script>
</head>
<body>
<div id="app"><div class="Layout" data-v-d8b57b2d><!--[--><!--]--><!--[--><span tabindex="-1" data-v-c8291ffa></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-c8291ffa> Skip to content </a><!--]--><!----><header class="VPNav" data-v-d8b57b2d data-v-7ad780c2><div class="VPNavBar" data-v-7ad780c2 data-v-9fd4d1dd><div class="wrapper" data-v-9fd4d1dd><div class="container" data-v-9fd4d1dd><div class="title" data-v-9fd4d1dd><div class="VPNavBarTitle has-sidebar" data-v-9fd4d1dd data-v-0ad69264><a class="title" href="/" data-v-0ad69264><!--[--><!--]--><!--[--><img class="VPImage logo" src="/logo.svg" alt data-v-ab19afbb><!--]--><span data-v-0ad69264>小蚂蚁云</span><!--[--><!--]--></a></div></div><div class="content" data-v-9fd4d1dd><div class="content-body" data-v-9fd4d1dd><!--[--><!--]--><div class="VPNavBarSearch search" data-v-9fd4d1dd><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><span class="vp-icon DocSearch-Search-Icon"></span><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-9fd4d1dd data-v-afb2845e><span id="main-nav-aria-label" class="visually-hidden" data-v-afb2845e> Main Navigation </span><!--[--><!--[--><a class="VPLink link vp-external-link-icon VPNavBarMenuLink" href="https://www.rxthink.cn" target="_blank" rel="noreferrer" tabindex="0" data-v-afb2845e data-v-08fbf4b6><!--[--><span data-v-08fbf4b6>官网</span><!--]--></a><!--]--><!--[--><a class="VPLink link vp-external-link-icon VPNavBarMenuLink" href="https://www.rxthink.cn/goods/detail/2" target="_blank" rel="noreferrer" tabindex="0" data-v-afb2845e data-v-08fbf4b6><!--[--><span data-v-08fbf4b6>授权</span><!--]--></a><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-afb2845e data-v-af5898d3><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-af5898d3><span class="text" data-v-af5898d3><!----><span data-v-af5898d3>部署文档</span><span class="vpi-chevron-down text-icon" data-v-af5898d3></span></span></button><div class="menu" data-v-af5898d3><div class="VPMenu" data-v-af5898d3 data-v-20ed86d6><div class="items" data-v-20ed86d6><!--[--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://docs.thinkphp6.layui.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF混编版ThinkPHP6+Layui版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://docs.thinkphp6.elevue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离ThinkPHP6+ElementPlus版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://docs.thinkphp6.antdvue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离ThinkPHP6+AntDesign版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://docs.thinkphp6.naivevue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离ThinkPHP6+NaiveUI版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://docs.thinkphp8.layui.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF混编版ThinkPHP8+Layui版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://docs.thinkphp8.elevue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离ThinkPHP8+ElementPlus版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://docs.thinkphp8.antdvue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离ThinkPHP8+AntDesign版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://docs.thinkphp8.naivevue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离ThinkPHP8+NaiveUI版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://docs.laravel13.layui.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF混编版Laravel13+Layui版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://docs.laravel13.elevue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离Laravel13+ElementPlus版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://docs.laravel13.antdvue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离Laravel13+AntDesign版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://docs.laravel13.naivevue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离Laravel13+NaiveUI版本<!--]--></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-afb2845e data-v-af5898d3><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-af5898d3><span class="text" data-v-af5898d3><!----><span data-v-af5898d3>在线演示</span><span class="vpi-chevron-down text-icon" data-v-af5898d3></span></span></button><div class="menu" data-v-af5898d3><div class="VPMenu" data-v-af5898d3 data-v-20ed86d6><div class="items" data-v-20ed86d6><!--[--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://manage.thinkphp6.layui.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF混编版ThinkPHP6+Layui版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://manage.thinkphp6.elevue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离ThinkPHP6+ElementPlus版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://manage.thinkphp6.antdvue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离ThinkPHP6+AntDesign版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://manage.thinkphp6.naivevue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离ThinkPHP6+NaiveUI版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://manage.thinkphp8.layui.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF混编版ThinkPHP8+Layui版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://manage.thinkphp8.elevue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离ThinkPHP8+ElementPlus版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://manage.thinkphp8.antdvue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离ThinkPHP8+AntDesign版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://manage.thinkphp8.naivevue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离ThinkPHP8+NaiveUI版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://manage.laravel13.layui.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF混编版Laravel13+Layui版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://manage.laravel13.elevue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离Laravel13+ElementPlus版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://manage.laravel13.antdvue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离Laravel13+AntDesign版本<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="http://manage.laravel13.naivevue.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->RXThinkCMF前后端分离Laravel13+NaiveUI版本<!--]--></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/zh/other/sponsor.html" tabindex="0" data-v-afb2845e data-v-08fbf4b6><!--[--><span data-v-08fbf4b6>广告赞助</span><!--]--></a><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-afb2845e data-v-af5898d3><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-af5898d3><span class="text" data-v-af5898d3><!----><span data-v-af5898d3>相关链接</span><span class="vpi-chevron-down text-icon" data-v-af5898d3></span></span></button><div class="menu" data-v-af5898d3><div class="VPMenu" data-v-af5898d3 data-v-20ed86d6><div class="items" data-v-20ed86d6><!--[--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="https://www.rxthink.cn" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->官方网站<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="https://gitee.com/rxthinkcmf/RXThinkCMF_ThinkPhp8_NaiveVue" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->Gitee 仓库<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="https://www.thinkphp.cn/" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->ThinkPHP 官网<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="https://cn.vuejs.org/" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->Vue3 文档<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-20ed86d6 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="https://www.naiveui.com/" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->NaiveUI<!--]--></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-9fd4d1dd data-v-3f90c1a5><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-3f90c1a5 data-v-be9742d9 data-v-b4ccac88><span class="check" data-v-b4ccac88><span class="icon" data-v-b4ccac88><!--[--><span class="vpi-sun sun" data-v-be9742d9></span><span class="vpi-moon moon" data-v-be9742d9></span><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-9fd4d1dd data-v-ef6192dc data-v-e71e869c><!--[--><a class="VPSocialLink no-icon" href="https://gitee.com/rxthinkcmf/RXThinkCMF_ThinkPhp8_NaiveVue" aria-label="github" target="_blank" rel="noopener" data-v-e71e869c data-v-358b6670><span class="vpi-social-github" /></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-9fd4d1dd data-v-f953d92f data-v-af5898d3><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-af5898d3><span class="vpi-more-horizontal icon" data-v-af5898d3></span></button><div class="menu" data-v-af5898d3><div class="VPMenu" data-v-af5898d3 data-v-20ed86d6><!----><!--[--><!--[--><!----><div class="group" data-v-f953d92f><div class="item appearance" data-v-f953d92f><p class="label" data-v-f953d92f>Appearance</p><div class="appearance-action" data-v-f953d92f><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-f953d92f data-v-be9742d9 data-v-b4ccac88><span class="check" data-v-b4ccac88><span class="icon" data-v-b4ccac88><!--[--><span class="vpi-sun sun" data-v-be9742d9></span><span class="vpi-moon moon" data-v-be9742d9></span><!--]--></span></span></button></div></div></div><div class="group" data-v-f953d92f><div class="item social-links" data-v-f953d92f><div class="VPSocialLinks social-links-list" data-v-f953d92f data-v-e71e869c><!--[--><a class="VPSocialLink no-icon" href="https://gitee.com/rxthinkcmf/RXThinkCMF_ThinkPhp8_NaiveVue" aria-label="github" target="_blank" rel="noopener" data-v-e71e869c data-v-358b6670><span class="vpi-social-github" /></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-9fd4d1dd data-v-6bee1efd><span class="container" data-v-6bee1efd><span class="top" data-v-6bee1efd></span><span class="middle" data-v-6bee1efd></span><span class="bottom" data-v-6bee1efd></span></span></button></div></div></div></div><div class="divider" data-v-9fd4d1dd><div class="divider-line" data-v-9fd4d1dd></div></div></div><!----></header><div class="VPLocalNav has-sidebar empty" data-v-d8b57b2d data-v-2488c25a><div class="container" data-v-2488c25a><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-2488c25a><span class="vpi-align-left menu-icon" data-v-2488c25a></span><span class="menu-text" data-v-2488c25a>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-2488c25a data-v-883964e0><button data-v-883964e0>Return to top</button><!----></div></div></div><aside class="VPSidebar" data-v-d8b57b2d data-v-42c4c606><div class="curtain" data-v-42c4c606></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-42c4c606><span class="visually-hidden" id="sidebar-aria-label" data-v-42c4c606> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="no-transition group" data-v-51288d80><section class="VPSidebarItem level-0 collapsible" data-v-51288d80 data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h2 class="text" data-v-edd2eed8>📖 1. 了解项目</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/introduction.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>1.1 项目介绍</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/why.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>1.2 为什么选择我们</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/directory.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>1.3 项目目录结构</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/course.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>1.4 新手入门指南</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/tech-stack.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>1.5 技术栈说明</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/changelog.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>1.6 更新日志</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-51288d80><section class="VPSidebarItem level-0 collapsible" data-v-51288d80 data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h2 class="text" data-v-edd2eed8>🚀 2. 快速入门</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/quickstart/environment.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>2.1 开发环境准备</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/quickstart/backend-start.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>2.2 后端服务启动</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/quickstart/frontend-start.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>2.3 前端服务启动</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/quickstart/database-init.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>2.4 数据库初始化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/quickstart/env-vars.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>2.5 环境变量配置</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/quickstart/first-api.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>2.6 第一个接口调试</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/quickstart/docker.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>2.7 Docker 快速体验</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/quickstart/faq.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>2.8 常见问题 FAQ</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-51288d80><section class="VPSidebarItem level-0 collapsible" data-v-51288d80 data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h2 class="text" data-v-edd2eed8>🧪 3. 模块开发实战</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/guide/overview.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>3.1 概述与目标</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/guide/database.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>3.2 数据库建表</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/guide/model.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>3.3 模型层开发</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/guide/validator.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>3.4 验证器开发</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/guide/logic.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>3.5 逻辑层开发</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/guide/controller.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>3.6 控制器开发</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/guide/route.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>3.7 路由注册</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/guide/permission.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>3.8 权限节点配置</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/guide/frontend-integration.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>3.9 前端联调指引</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/guide/code-list.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>3.10 完整代码清单</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/guide/faq.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>3.11 常见问题与排错</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-51288d80><section class="VPSidebarItem level-0 collapsible has-active" data-v-51288d80 data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h2 class="text" data-v-edd2eed8>🏛️ 4. 架构设计</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/architecture/overview.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>4.1 整体架构概览</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/architecture/request-flow.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>4.2 请求处理链路</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/architecture/backend-layer.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>4.3 后端分层架构</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/architecture/frontend-layer.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>4.4 前端分层架构</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/architecture/directory-design.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>4.5 目录结构设计</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/architecture/base-classes.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>4.6 核心基类体系</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/architecture/cross-cutting.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>4.7 横切机制</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/architecture/cache.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>4.8 缓存架构设计</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/architecture/database-design.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>4.9 数据库设计</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/architecture/security.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>4.10 安全架构设计</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/architecture/extensibility.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>4.11 扩展性设计</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-51288d80><section class="VPSidebarItem level-0 collapsible" data-v-51288d80 data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h2 class="text" data-v-edd2eed8>🔐 5. 核心功能</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><section class="VPSidebarItem level-1 collapsible" data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h3 class="text" data-v-edd2eed8>认证与安全</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/jwt.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.1 用户认证(JWT)</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/auth-flow.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.2 认证流程实战</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/captcha.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.3 验证码机制</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/rbac.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.4 权限管理(RBAC)</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/cors.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.5 跨域资源共享</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/password.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.6 密码加密服务</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/demo-mode.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.7 演示模式</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible" data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h3 class="text" data-v-edd2eed8>数据与配置</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/tenant.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.8 多租户隔离</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/data-scope.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.9 数据权限</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/dict.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.10 字典模块</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/dict-guide.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.11 字典配置与使用</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/config.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.12 系统配置管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/param.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.13 系统参数管理</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible" data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h3 class="text" data-v-edd2eed8>日志与监控</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/operation-log.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.14 操作日志</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/login-log.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.15 登录日志</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/exception.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.16 异常与响应处理</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible" data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h3 class="text" data-v-edd2eed8>防护与治理</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/idempotent.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.17 防重复提交</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible" data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h3 class="text" data-v-edd2eed8>注解系统</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/core/attributes.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>5.18 注解系统总览</p><!--]--></a><!----></div><!----></div><!--]--></div></section><!--]--></div></section></div><div class="no-transition group" data-v-51288d80><section class="VPSidebarItem level-0 collapsible" data-v-51288d80 data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h2 class="text" data-v-edd2eed8>📦 6. 业务模块</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/user.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.1 用户管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/role.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.2 角色管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/menu.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.3 菜单管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/dept.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.4 部门管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/level.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.5 职级管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/position.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.6 岗位管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/article.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.7 文章管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/content.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.8 公告与链接管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/city.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.9 行政区划管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/category.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.10 分类管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/job.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.11 定时任务</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/param.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.12 参数管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/tenant.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.13 租户管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/filetemplate.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.14 文件模板管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/modules/index.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>6.15 首页与个人中心</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-51288d80><section class="VPSidebarItem level-0 collapsible" data-v-51288d80 data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h2 class="text" data-v-edd2eed8>🧰 7. 文件处理</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/tools/upload.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>7.1 文件上传全流程</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/tools/upload-config.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>7.2 上传配置详解</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/tools/rich-text.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>7.3 富文本处理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/tools/excel.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>7.4 数据导入导出</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/tools/file-components.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>7.5 前端文件组件</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/tools/db-migrate.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>7.6 数据库迁移工具</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-51288d80><section class="VPSidebarItem level-0 collapsible" data-v-51288d80 data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h2 class="text" data-v-edd2eed8>🔗 8. 接口规范与对接</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/api-spec/response.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>8.1 统一响应格式</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/api-spec/error-code.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>8.2 错误码对照表</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/api-spec/pagination.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>8.3 分页查询规范</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/api-spec/upload.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>8.4 文件上传接口</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/api-spec/dict-api.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>8.5 字典数据接口</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/api-spec/token.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>8.6 Token 使用说明</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/api-spec/overview.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>8.7 API 接口总览</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-51288d80><section class="VPSidebarItem level-0 collapsible" data-v-51288d80 data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h2 class="text" data-v-edd2eed8>🖥️ 9. 前端开发</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><section class="VPSidebarItem level-1 collapsible" data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h3 class="text" data-v-edd2eed8>工程基础</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/overview.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.1 前端工程概述</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/directory.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.2 目录结构详解</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/env-config.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.3 环境与构建配置</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible" data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h3 class="text" data-v-edd2eed8>核心机制</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/http.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.4 HTTP 请求封装</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/router.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.5 路由与动态菜单</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/store.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.6 状态管理(Pinia)</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/permission.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.7 权限控制</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/login.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.8 登录流程</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible" data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h3 class="text" data-v-edd2eed8>公共组件</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/display-components.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.9 数据展示组件</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/form-components.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.10 数据录入组件</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/excel-components.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.11 Excel 导入导出组件</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible" data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h3 class="text" data-v-edd2eed8>开发实践</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/new-page.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.12 新增页面开发步骤</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/api-module.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.13 API 模块编写规范</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/style.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.14 样式与主题定制</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/layout.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.15 布局系统</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/utils.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.16 工具函数</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/frontend/i18n.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>9.17 国际化(i18n)</p><!--]--></a><!----></div><!----></div><!--]--></div></section><!--]--></div></section></div><div class="no-transition group" data-v-51288d80><section class="VPSidebarItem level-0 collapsible" data-v-51288d80 data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h2 class="text" data-v-edd2eed8>🔧 10. 代码生成器</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/generator/overview.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>10.1 概述与架构</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/generator/cli.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>10.2 CLI 命令行使用</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/generator/web-ui.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>10.3 Web 管理界面</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/generator/parser.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>10.4 表结构解析引擎</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/generator/code-engine.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>10.5 代码生成引擎</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/generator/templates.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>10.6 自定义模板开发</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/generator/config.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>10.7 配置文件详解</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/generator/demo.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>10.8 实战案例</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/generator/faq.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>10.9 常见问题</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-51288d80><section class="VPSidebarItem level-0 collapsible" data-v-51288d80 data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h2 class="text" data-v-edd2eed8>⚙️ 11. 运维部署</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/deploy/checklist.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>11.1 部署 Checklist</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/deploy/env-plan.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>11.2 环境规划</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/deploy/db-migrate.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>11.3 数据库迁移</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/deploy/backend.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>11.4 后端部署</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/deploy/frontend.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>11.5 前端部署</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/deploy/docker.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>11.6 Docker 生产部署</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/deploy/performance.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>11.7 性能调优</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/deploy/security.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>11.8 安全加固清单</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/deploy/backup.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>11.9 备份与恢复</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/deploy/troubleshooting.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>11.10 故障排查手册</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/deploy/ci-cd.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>11.11 CI/CD 流水线</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-51288d80><section class="VPSidebarItem level-0 collapsible" data-v-51288d80 data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h2 class="text" data-v-edd2eed8>📋 12. 规范标准</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><section class="VPSidebarItem level-1 collapsible" data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h3 class="text" data-v-edd2eed8>⭐ 必须遵守</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/standards/api-response.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>12.1 API 响应规范</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/standards/pagination.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>12.2 分页查询规范</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/standards/git.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>12.3 Git 提交规范</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible" data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h3 class="text" data-v-edd2eed8>📌 建议遵守</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/standards/deletion.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>12.4 数据删除规范</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/standards/code-review.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>12.5 代码审查清单</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/standards/backend-code.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>12.6 后端编码规范</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/standards/frontend-code.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>12.7 前端编码规范</p><!--]--></a><!----></div><!----></div><!--]--></div></section><!--]--></div></section></div><div class="no-transition group" data-v-51288d80><section class="VPSidebarItem level-0 collapsible" data-v-51288d80 data-v-edd2eed8><div class="item" role="button" tabindex="0" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><h2 class="text" data-v-edd2eed8>📄 附录</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-edd2eed8><span class="vpi-chevron-right caret-icon" data-v-edd2eed8></span></div></div><div class="items" data-v-edd2eed8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/appendix/faq.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>A. 常见问题汇总</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/appendix/database-tables.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>B. 数据库表结构速查</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/appendix/config-reference.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>C. 配置项速查</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/appendix/functions.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>D. 公共函数速查</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/appendix/api-cheatsheet.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>E. API 接口速查表</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/appendix/middleware.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>F. 中间件执行顺序</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/appendix/components.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>G. 前端组件速查</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/appendix/stores.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>H. 前端 Store 速查</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/appendix/enums.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>I. 前端 Enums 速查</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/appendix/glossary.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>J. 术语表</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/other/contributing.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>K. 贡献指南</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/other/declare.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>L. 免责声明</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link link" href="/zh/other/sponsor.html" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>M. 广告赞助</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-edd2eed8><div class="item" data-v-edd2eed8><div class="indicator" data-v-edd2eed8></div><a class="VPLink link vp-external-link-icon link" href="https://gitee.com/rxthinkcmf/RXThinkCMF_ThinkPhp8_NaiveVue" target="_blank" rel="noreferrer" data-v-edd2eed8><!--[--><p class="text" data-v-edd2eed8>N. 开源协议</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-d8b57b2d data-v-9a6c75ad><div class="VPDoc has-sidebar has-aside" data-v-9a6c75ad data-v-e6f2a212><!--[--><!--]--><div class="container" data-v-e6f2a212><div class="aside" data-v-e6f2a212><div class="aside-curtain" data-v-e6f2a212></div><div class="aside-container" data-v-e6f2a212><div class="aside-content" data-v-e6f2a212><div class="VPDocAside" data-v-e6f2a212 data-v-cb998dce><!--[--><!--]--><!--[--><!--]--><nav aria-labelledby="doc-outline-aria-label" class="VPDocAsideOutline" data-v-cb998dce data-v-f610f197><div class="content" data-v-f610f197><div class="outline-marker" data-v-f610f197></div><div aria-level="2" class="outline-title" id="doc-outline-aria-label" role="heading" data-v-f610f197>本页内容</div><ul class="VPDocOutlineItem root" data-v-f610f197 data-v-53c99d69><!--[--><!--]--></ul></div></nav><!--[--><!--]--><div class="spacer" data-v-cb998dce></div><!--[--><!--[--><!--[--><!--[--><!--[--><div class="VPDocAsideSponsors" data-v-46d2db61><div class="VPSponsors vp-sponsor aside"><!--[--><section class="vp-sponsor-section"><!----><div class="VPSponsorsGrid vp-sponsor-grid mini"><!--[--><div class="vp-sponsor-grid-item"><a class="vp-sponsor-grid-link" href="https://www.rxthink.cn" target="_blank" rel="sponsored noopener"><article class="vp-sponsor-grid-box"><h4 class="visually-hidden">Become a sponsor</h4><img class="vp-sponsor-grid-image" src="/sponsor/rxthinkcmf.png" alt="Become a sponsor"></article></a></div><!--]--></div></section><section class="vp-sponsor-section"><!----><div class="VPSponsorsGrid vp-sponsor-grid xmini"><!--[--><div class="vp-sponsor-grid-item"><a class="vp-sponsor-grid-link" href="https://www.rxthink.cn" target="_blank" rel="sponsored noopener"><article class="vp-sponsor-grid-box"><h4 class="visually-hidden">企业级中台解决方案</h4><img class="vp-sponsor-grid-image" src="/sponsor/rxthinkcmf.png" alt="企业级中台解决方案"></article></a></div><div class="vp-sponsor-grid-item"><a class="vp-sponsor-grid-link" href="https://www.rxthink.cn" target="_blank" rel="sponsored noopener"><article class="vp-sponsor-grid-box"><h4 class="visually-hidden">企业级中台解决方案</h4><img class="vp-sponsor-grid-image" src="/sponsor/rxthinkcmf.png" alt="企业级中台解决方案"></article></a></div><!--]--></div></section><!--]--></div></div><a class="banner mp" href="https://www.rxthink.cn" target="_blank" data-v-46d2db61><img width="22" height="22" src="/sponsor/rxthinkcmf.png" data-v-46d2db61><span data-v-46d2db61><p class="extra-info" data-v-46d2db61>赋能开发者</p><p class="heading" data-v-46d2db61>企业级中台解决方案</p><p class="extra-info" data-v-46d2db61>助力企业发展</p></span></a><a class="banner cert" href="https://www.rxthink.cn" target="_blank" data-v-46d2db61><img width="22" height="22" src="/sponsor/rxthinkcmf.png" data-v-46d2db61><span data-v-46d2db61><p class="extra-info" data-v-46d2db61>赋能开发者</p><p class="heading" data-v-46d2db61>企业级中台解决方案</p><p class="extra-info" data-v-46d2db61>助力企业发展</p></span></a><!--]--><!--]--><!--]--><!--]--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-e6f2a212><div class="content-container" data-v-e6f2a212><!--[--><!--]--><main class="main" data-v-e6f2a212><div style="position:relative;" class="vp-doc _zh_architecture_request-flow" data-v-e6f2a212><div><h1 id="_4-2-请求处理链路" tabindex="-1">4.2 请求处理链路 <a class="header-anchor" href="#_4-2-请求处理链路" aria-label="Permalink to &quot;4.2 请求处理链路&quot;">​</a></h1><div class="tip custom-block"><p class="custom-block-title">链路概览</p><p>一个典型的 API 请求经过以下阶段:浏览器 → Nginx → CORS 中间件 → Auth 中间件(JWT 认证 + RBAC 鉴权)→ Tenant 中间件 → Demo 中间件 → Log 中间件 → 控制器 → 逻辑层 → 模型层 → 数据库 → 响应序列化 → 浏览器</p></div><p>本节以 <code>POST /api/example/add</code> 添加案例为例,逐步拆解完整链路。</p><h2 id="第一阶段-网络层" tabindex="-1">第一阶段:网络层 <a class="header-anchor" href="#第一阶段-网络层" aria-label="Permalink to &quot;第一阶段:网络层&quot;">​</a></h2><h3 id="_1-浏览器发起请求" tabindex="-1">1. 浏览器发起请求 <a class="header-anchor" href="#_1-浏览器发起请求" aria-label="Permalink to &quot;1. 浏览器发起请求&quot;">​</a></h3><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// 前端 Axios 调用(ui/src/api/tool/example.ts)</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">export</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> exampleAdd</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#FFB86C;--shiki-dark-font-style:italic;--shiki-light:#B07D48;--shiki-light-font-style:inherit;">data</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#2E8F82;--shiki-light-font-style:inherit;"> any</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> http</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">.</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">({</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;"> url</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">/example/add</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;"> method</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">POST</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;"> data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">, </span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// { name: &#39;测试案例&#39;, status: 1, sort: 0 }</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> });</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><p>前端通过 Axios 发起 HTTP POST 请求,携带:</p><ul><li><code>Authorization: Bearer &lt;JWT Token&gt;</code> 请求头(由请求拦截器自动添加)</li><li><code>Content-Type: application/json</code> 请求头</li><li>JSON 请求体</li></ul><h3 id="_2-Nginx-反向代理-生产环境-" tabindex="-1">2. Nginx 反向代理(生产环境) <a class="header-anchor" href="#_2-Nginx-反向代理-生产环境-" aria-label="Permalink to &quot;2. Nginx 反向代理(生产环境)&quot;">​</a></h3><div class="language-nginx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">nginx</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">location</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#59873A;"> /api/ </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">{</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> proxy_pass </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">http://127.0.0.1:8000</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> proxy_set_header </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">Host </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">$</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">host</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> proxy_set_header </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">X-Real-IP </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">$</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">remote_addr</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> proxy_set_header </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">X-Forwarded-For </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">$</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">proxy_add_x_forwarded_for</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">}</span></span></code></pre></div><p>开发环境下,Vite 开发服务器将 <code>/api</code> 请求代理到后端:</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// ui/vite.config.ts</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#59873A;">server</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#59873A;"> proxy</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">/api</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;"> target</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">http://localhost:8000</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#998418;"> changeOrigin</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;"> true</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> },</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> },</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><h2 id="第二阶段-路由解析" tabindex="-1">第二阶段:路由解析 <a class="header-anchor" href="#第二阶段-路由解析" aria-label="Permalink to &quot;第二阶段:路由解析&quot;">​</a></h2><h3 id="_3-ThinkPHP-入口" tabindex="-1">3. ThinkPHP 入口 <a class="header-anchor" href="#_3-ThinkPHP-入口" aria-label="Permalink to &quot;3. ThinkPHP 入口&quot;">​</a></h3><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>public/index.php → 引导框架 → 路由解析 route/app.php</span></span></code></pre></div><h3 id="_4-路由匹配" tabindex="-1">4. 路由匹配 <a class="header-anchor" href="#_4-路由匹配" aria-label="Permalink to &quot;4. 路由匹配&quot;">​</a></h3><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// route/app.php</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// 公开接口(无需认证)</span></span>
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Route</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">group</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">api</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ()</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Route</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">post</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">login</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">LoginController/login</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Route</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">get</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">captcha</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">LoginController/captcha</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">});</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// 需认证接口</span></span>
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Route</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">group</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">api</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ()</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Route</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">group</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">example</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ()</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Route</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">post</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">add</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">ExampleController/add</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // ← 匹配到此处</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> });</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">})</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">middleware</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">([</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> \</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">app</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;">\</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">middleware</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;">\</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">AuthMiddleware</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">class</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // JWT 认证 + 权限校验</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> \</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">app</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;">\</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">middleware</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;">\</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">TenantMiddleware</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">class</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 租户上下文</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> \</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">app</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;">\</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">middleware</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;">\</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">DemoMiddleware</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">class</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 演示环境拦截</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> \</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">app</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;">\</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">middleware</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;">\</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">LogMiddleware</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">class</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 操作日志</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]);</span></span></code></pre></div><p>路由匹配到 <code>POST api/example/add</code> → <code>ExampleController::add()</code>,同时绑定四个中间件。</p><h2 id="第三阶段-中间件链-按顺序执行-" tabindex="-1">第三阶段:中间件链(按顺序执行) <a class="header-anchor" href="#第三阶段-中间件链-按顺序执行-" aria-label="Permalink to &quot;第三阶段:中间件链(按顺序执行)&quot;">​</a></h2><h3 id="_5-CorsMiddleware-全局中间件-" tabindex="-1">5. CorsMiddleware(全局中间件) <a class="header-anchor" href="#_5-CorsMiddleware-全局中间件-" aria-label="Permalink to &quot;5. CorsMiddleware(全局中间件)&quot;">​</a></h3><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// app/middleware/CorsMiddleware.php</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">public</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> handle</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> \</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Closure</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">next</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">:</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Response</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 处理 OPTIONS 预检请求</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">isOptions</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">())</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">response</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Response</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">create</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">html</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 204</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> else</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">response</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">next</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 设置跨域响应头</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">response</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">header</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">([</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">Access-Control-Allow-Origin</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">origin</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">Access-Control-Allow-Methods</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">GET, POST, PUT, DELETE, PATCH, OPTIONS</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">Access-Control-Allow-Headers</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">Content-Type, Authorization, ...</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">Access-Control-Allow-Credentials</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">true</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ]);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">response</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><ul><li>每个请求都经过(全局中间件)</li><li>OPTIONS 预检请求直接返回 204</li><li>普通请求附加 CORS 响应头</li></ul><h3 id="_6-AuthMiddleware-JWT-认证-权限校验-" tabindex="-1">6. AuthMiddleware(JWT 认证 + 权限校验) <a class="header-anchor" href="#_6-AuthMiddleware-JWT-认证-权限校验-" aria-label="Permalink to &quot;6. AuthMiddleware(JWT 认证 + 权限校验)&quot;">​</a></h3><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// app/middleware/AuthMiddleware.php</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">public</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> handle</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> \</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Closure</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">next</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">:</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Response</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 1. 检查排除路由(login/captcha 等直接放行)</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">path</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">pathinfo</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">();</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> foreach</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">exceptList</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> as</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">except</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">strpos</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">path</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">except</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> !==</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;"> false</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">next</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 2. 从请求头获取 Token</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">token</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Jwt</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">getTokenFromHeader</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">();</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">empty</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">token</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">))</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> json</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">([</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 401</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">未提供认证令牌</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 3. 解析 Token,校验签名和有效期</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> try</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">decoded</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Jwt</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">decode</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">token</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> catch</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;">\</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">RuntimeException</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">e</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> json</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">([</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 401</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">e</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">getMessage</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">()]);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 4. 校验 token 类型必须为 access</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">decoded</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">type</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ??</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> !==</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">access</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> json</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">([</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 401</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">无效的认证令牌</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 5. 注入用户信息到 Request</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">userInfo</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">decoded</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 6. 读取 #[Permission] 注解,校验权限</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">permission</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> AttributeService</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">getPermission</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">controllerClass</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">action</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">permission</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> !==</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;"> null</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">hasPermission</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> $</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">checkPermission</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">decoded</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">uid</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">permission</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">code</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">!</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">$</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">hasPermission</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> json</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">([</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 403</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">无访问权限</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">next</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><p>处理流程:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>请求进入</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ├─ 路径在排除列表? → 直接放行</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ├─ 提取 Authorization: Bearer &lt;token&gt;</span></span>
<span class="line"><span> │ └─ 为空 → 返回 401</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ├─ Jwt::decode($token) 解析验证</span></span>
<span class="line"><span> │ └─ 失败(过期/签名错误)→ 返回 401</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ├─ 校验 type === &#39;access&#39;</span></span>
<span class="line"><span> │ └─ 不是 → 返回 401</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ├─ 注入 $request-&gt;userInfo = {uid, username, type, exp}</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ├─ 读取 #[Permission] 注解</span></span>
<span class="line"><span> │ ├─ 无注解 → 跳过权限校验</span></span>
<span class="line"><span> │ └─ 有注解 → checkPermission()</span></span>
<span class="line"><span> │ ├─ uid === 1 → 直接放行(超级管理员)</span></span>
<span class="line"><span> │ └─ 查询 UserRole → RoleMenu → Menu.permission</span></span>
<span class="line"><span> │ ├─ 包含 → 放行</span></span>
<span class="line"><span> │ └─ 不包含 → 返回 403</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> └─ 放行 → 进入下一个中间件</span></span></code></pre></div><h3 id="_7-TenantMiddleware-租户上下文-" tabindex="-1">7. TenantMiddleware(租户上下文) <a class="header-anchor" href="#_7-TenantMiddleware-租户上下文-" aria-label="Permalink to &quot;7. TenantMiddleware(租户上下文)&quot;">​</a></h3><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// app/middleware/TenantMiddleware.php</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">public</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> handle</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> \</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Closure</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">next</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">:</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Response</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">userInfo</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">userInfo</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ??</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;"> null</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">userId</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">userInfo</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">uid</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ??</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 0</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">user</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> User</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">find</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">userId</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenantId</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">user</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenant_id</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ??</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 0</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 注入租户上下文</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenantId</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenantId</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">isSuperAdmin</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenantId</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ==</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 0</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 非超级管理员校验租户状态</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenantId</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> &gt;</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 0</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenant</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Tenant</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">find</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenantId</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">!</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">$</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenant</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ||</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenant</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">status</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> !=</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 1</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> json</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">([</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 403</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">租户已被禁用</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenant</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">expire_time</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> &amp;&amp;</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> strtotime</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenant</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">expire_time</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> &lt;</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> time</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">())</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> json</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">([</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 403</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">租户已过期</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenantInfo</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">tenant</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">next</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><p>注入内容:</p><ul><li><code>$request-&gt;tenantId</code> — 租户 ID(0=超级管理员)</li><li><code>$request-&gt;isSuperAdmin</code> — 是否超级管理员</li><li><code>$request-&gt;tenantInfo</code> — 租户信息对象</li></ul><h3 id="_8-DemoMiddleware-演示环境拦截-" tabindex="-1">8. DemoMiddleware(演示环境拦截) <a class="header-anchor" href="#_8-DemoMiddleware-演示环境拦截-" aria-label="Permalink to &quot;8. DemoMiddleware(演示环境拦截)&quot;">​</a></h3><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// app/middleware/DemoMiddleware.php</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">public</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> handle</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> \</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Closure</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">next</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">:</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Response</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 非演示环境直接放行</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">!</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">env</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">app_demo</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;"> false</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">))</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">next</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // GET 请求放行(读操作)</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">strtoupper</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">method</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">())</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ===</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">GET</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">next</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 检查 #[DemoAllow] 注解</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">AttributeService</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">hasDemoAllow</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">controllerClass</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">action</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">))</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">next</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 拦截写操作</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> json</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">([</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 403</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">演示环境,禁止操作</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><h3 id="_9-LogMiddleware-操作日志-" tabindex="-1">9. LogMiddleware(操作日志) <a class="header-anchor" href="#_9-LogMiddleware-操作日志-" aria-label="Permalink to &quot;9. LogMiddleware(操作日志)&quot;">​</a></h3><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// app/middleware/LogMiddleware.php</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">public</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> handle</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> \</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Closure</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">next</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">:</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Response</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">startTime</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> microtime</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;">true</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 执行后续中间件和控制器</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">response</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">next</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 写操作始终记录</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">in_array</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">method</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> [</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">POST</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">PUT</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">DELETE</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">PATCH</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]))</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 读取 #[Log] 注解</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">logAttr</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> AttributeService</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">getLog</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">controllerClass</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">action</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 组装日志数据</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">logData</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> [</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">title</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">logAttr</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">?-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">title</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ?:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">path</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">type</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">logAttr</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">?-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">type</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ?:</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> $</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">guessType</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">method</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">),</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">method</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">method</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">url</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">url</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(),</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">param</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> json_encode</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">request</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">param</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">()),</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">ip</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">requestInfo</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">getIp</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(),</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">location</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">requestInfo</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">getIpLocation</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(),</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">os</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">requestInfo</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">getOs</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(),</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">browser</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">requestInfo</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">getBrowser</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(),</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">consume_time</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">=&gt;</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> round</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">((</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">microtime</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;">true</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> -</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">startTime</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> *</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 1000</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">),</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">status</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> $</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">detectStatus</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">response</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">getContent</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">()),</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ];</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 写入数据库(失败不影响主业务)</span></span>
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> OperationLog</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">create</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">logData</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">response</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><h2 id="第四阶段-控制器层" tabindex="-1">第四阶段:控制器层 <a class="header-anchor" href="#第四阶段-控制器层" aria-label="Permalink to &quot;第四阶段:控制器层&quot;">​</a></h2><h3 id="_10-ExampleController-add-" tabindex="-1">10. ExampleController::add() <a class="header-anchor" href="#_10-ExampleController-add-" aria-label="Permalink to &quot;10. ExampleController::add()&quot;">​</a></h3><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// app/controller/ExampleController.php</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">#[</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Log</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">案例演示-新增记录</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Log</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;">TYPE_ADD</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">新增案例演示:{name}</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">]</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">#[</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Permission</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">sys:example:add</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">添加案例演示</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">]</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">public</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> add</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">()</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">:</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Json</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // getJsonBody() 获取前端 POST 提交的 JSON 数据</span></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // _add() 内部调用 $this-&gt;logic-&gt;add($data)</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#AB5959;--shiki-light-font-style:inherit;"> parent</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">_add</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;">$</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">logic</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> $</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">getJsonBody</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">());</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><p>控制器层职责:</p><ul><li>通过 <code>#[Permission]</code> 声明所需权限</li><li>通过 <code>#[Log]</code> 声明日志信息</li><li>获取参数,调用 Logic 层,返回响应</li></ul><h2 id="第五阶段-逻辑层" tabindex="-1">第五阶段:逻辑层 <a class="header-anchor" href="#第五阶段-逻辑层" aria-label="Permalink to &quot;第五阶段:逻辑层&quot;">​</a></h2><h3 id="_11-ExampleLogic-add-" tabindex="-1">11. ExampleLogic::add() <a class="header-anchor" href="#_11-ExampleLogic-add-" aria-label="Permalink to &quot;11. ExampleLogic::add()&quot;">​</a></h3><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// app/logic/ExampleLogic.php → 继承 BaseLogic</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// BaseLogic::add() 的完整流程:</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">public</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> add</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">array</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">:</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> int</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 1. 钩子:新增前(可修改数据,抛异常可拦截)</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> $</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">beforeAdd</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 2. 保留原始数据供 afterAdd 使用</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">originalData</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 3. 入库前转换:camelCase → snake_case</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> array_camel_to_snake</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 4. 租户ID自动填充</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> $</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">processTenantId</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 5. 文件字段:迁移临时文件,去掉域名</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> $</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">processFileFieldsOnSave</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 6. 富文本字段:迁移临时文件</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> $</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">processContentFieldsOnSave</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 7. 过滤非数据库字段</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">saveData</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> $</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">filterTableFields</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 8. 唯一性校验</span></span>
<span class="line"><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> $</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">checkUnique</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">saveData</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 9. 写入数据库</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">model</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> $</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">getModel</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">()</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">create</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">saveData</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">id</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">model</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">id</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 10. 钩子:新增后</span></span>
<span class="line"><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> $</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">afterAdd</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">id</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">originalData</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">id</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><h2 id="第六阶段-模型层" tabindex="-1">第六阶段:模型层 <a class="header-anchor" href="#第六阶段-模型层" aria-label="Permalink to &quot;第六阶段:模型层&quot;">​</a></h2><h3 id="_12-BaseModel-自动处理" tabindex="-1">12. BaseModel 自动处理 <a class="header-anchor" href="#_12-BaseModel-自动处理" aria-label="Permalink to &quot;12. BaseModel 自动处理&quot;">​</a></h3><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// app/model/Example.php</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">class</span><span style="--shiki-dark:#97E1F1;--shiki-light:#2E8F82;"> Example</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> extends</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#59873A;--shiki-light-font-style:inherit;"> BaseModel</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> protected</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">example</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// BaseModel 提供的能力:</span></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// 1. 全局查询范围 soft_delete → WHERE is_delete = 0</span></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// 2. onBeforeInsert → 自动填充 create_user, create_time</span></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// 3. onBeforeUpdate → 自动填充 update_user, update_time</span></span></code></pre></div><h3 id="_13-数据库执行" tabindex="-1">13. 数据库执行 <a class="header-anchor" href="#_13-数据库执行" aria-label="Permalink to &quot;13. 数据库执行&quot;">​</a></h3><p>ThinkPHP ORM 将操作转换为 SQL:</p><div class="language-sql vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">INSERT INTO</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;"> think_example (</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">name</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">status</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, sort, avatar, create_user, create_time)</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">VALUES</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;"> (</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">测试案例</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;">1</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;">0</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">admin</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">2026-09-20 12:00:00</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">);</span></span></code></pre></div><h2 id="第七阶段-响应返回" tabindex="-1">第七阶段:响应返回 <a class="header-anchor" href="#第七阶段-响应返回" aria-label="Permalink to &quot;第七阶段:响应返回&quot;">​</a></h2><h3 id="_14-响应序列化" tabindex="-1">14. 响应序列化 <a class="header-anchor" href="#_14-响应序列化" aria-label="Permalink to &quot;14. 响应序列化&quot;">​</a></h3><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// BaseController::_add()</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">protected</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> _add</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">BaseLogic</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">logic</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> array</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">:</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Json</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">id</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">logic</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">add</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> $</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">this</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-&gt;</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">success</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">([</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">id</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">id</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">],</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">添加成功</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// Result::success()</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">public</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> static</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> success</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> string</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">msg</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">操作成功</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">:</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Json</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> json</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">([</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 0</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">ok</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;"> true</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">msg</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &#39;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">data</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&#39;</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =&gt;</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#AB5959;--shiki-light-font-style:inherit;"> self</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">convertData</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">data</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">),</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // snake_case → camelCase</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ]);</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><h3 id="_15-浏览器接收响应" tabindex="-1">15. 浏览器接收响应 <a class="header-anchor" href="#_15-浏览器接收响应" aria-label="Permalink to &quot;15. 浏览器接收响应&quot;">​</a></h3><div class="language-json vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">json</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
<span class="line"><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;"> &quot;</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">code</span><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;">&quot;</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 0</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;"> &quot;</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">ok</span><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;">&quot;</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;"> true</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;"> &quot;</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">msg</span><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;">&quot;</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> &quot;</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">添加成功</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">&quot;</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
<span class="line"><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;"> &quot;</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">data</span><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;">&quot;</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
<span class="line"><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;"> &quot;</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">id</span><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;">&quot;</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 42</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><p>前端 Axios 拦截器统一处理:<code>code === 0</code> 时展示成功提示,否则展示错误信息。</p><h2 id="完整链路流程图" tabindex="-1">完整链路流程图 <a class="header-anchor" href="#完整链路流程图" aria-label="Permalink to &quot;完整链路流程图&quot;">​</a></h2><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>[浏览器]</span></span>
<span class="line"><span> │ POST /api/example/add</span></span>
<span class="line"><span> │ Authorization: Bearer &lt;token&gt;</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[Nginx / Vite Proxy] ── 反向代理转发</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[ThinkPHP 入口] ── public/index.php</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[路由解析] ── route/app.php 匹配 api/example/add</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[CorsMiddleware] ── 跨域校验通过(全局)</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[AuthMiddleware]</span></span>
<span class="line"><span> ├─ 提取 Token → Jwt::decode()</span></span>
<span class="line"><span> ├─ 校验 type === &#39;access&#39;</span></span>
<span class="line"><span> ├─ 注入 $request-&gt;userInfo</span></span>
<span class="line"><span> ├─ 读取 #[Permission] 注解</span></span>
<span class="line"><span> ├─ checkPermission() 权限校验</span></span>
<span class="line"><span> │ ├─ uid=1 → 跳过(超级管理员)</span></span>
<span class="line"><span> │ └─ UserRole → RoleMenu → Menu.permission</span></span>
<span class="line"><span> └─ 放行</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[TenantMiddleware]</span></span>
<span class="line"><span> ├─ 查询用户 tenant_id</span></span>
<span class="line"><span> ├─ 注入 $request-&gt;tenantId</span></span>
<span class="line"><span> └─ 校验租户状态(禁用/过期 → 403)</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[DemoMiddleware]</span></span>
<span class="line"><span> ├─ 非演示环境 → 放行</span></span>
<span class="line"><span> ├─ GET 请求 → 放行</span></span>
<span class="line"><span> └─ 有 #[DemoAllow] → 放行</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[LogMiddleware] ── 记录开始时间</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[ExampleController::add()]</span></span>
<span class="line"><span> ├─ #[Log] 注解元数据</span></span>
<span class="line"><span> ├─ #[Permission] 注解元数据</span></span>
<span class="line"><span> └─ parent::_add($this-&gt;logic, $data)</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[ExampleLogic::add()]</span></span>
<span class="line"><span> ├─ beforeAdd() 钩子</span></span>
<span class="line"><span> ├─ array_camel_to_snake() 键名转换</span></span>
<span class="line"><span> ├─ processTenantId() 租户填充</span></span>
<span class="line"><span> ├─ processFileFieldsOnSave() 文件处理</span></span>
<span class="line"><span> ├─ filterTableFields() 字段过滤</span></span>
<span class="line"><span> ├─ checkUnique() 唯一性校验</span></span>
<span class="line"><span> ├─ Model::create() 写入数据库</span></span>
<span class="line"><span> └─ afterAdd() 钩子</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[BaseModel]</span></span>
<span class="line"><span> ├─ onBeforeInsert → create_user, create_time</span></span>
<span class="line"><span> └─ 执行 SQL INSERT</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[数据库] ── 返回自增 ID</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼ 逐层返回响应</span></span>
<span class="line"><span>[Result::success()] ── {code:0, ok:true, msg:&quot;添加成功&quot;, data:{id:42}}</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[LogMiddleware] ── 记录操作日志(写操作)</span></span>
<span class="line"><span> │</span></span>
<span class="line"><span> ▼</span></span>
<span class="line"><span>[浏览器] ← JSON 响应</span></span></code></pre></div><h2 id="异常处理链路" tabindex="-1">异常处理链路 <a class="header-anchor" href="#异常处理链路" aria-label="Permalink to &quot;异常处理链路&quot;">​</a></h2><p>当链路中发生异常时,ExceptionHandle 统一捕获并返回标准响应:</p><table tabindex="0"><thead><tr><th>异常类型</th><th>触发场景</th><th>响应</th></tr></thead><tbody><tr><td><code>ValidateException</code></td><td>参数验证失败</td><td><code>{code:1, msg:&quot;参数验证失败&quot;, data:{错误明细}}</code></td></tr><tr><td><code>ModelNotFoundException</code></td><td>数据不存在</td><td><code>{code:1, msg:&quot;数据不存在&quot;}</code></td></tr><tr><td><code>RuntimeException (401)</code></td><td>JWT 过期/无效</td><td><code>{code:1, msg:&quot;token已过期&quot;}</code></td></tr><tr><td><code>HttpException</code></td><td>HTTP 错误</td><td><code>{code:1, msg:&quot;请求错误&quot;}</code></td></tr><tr><td><code>Exception</code></td><td>未捕获异常</td><td><code>{code:1, msg:&quot;操作失败&quot;}</code>(生产环境隐藏详情)</td></tr></tbody></table><div class="warning custom-block"><p class="custom-block-title">异常处理原则</p><p>所有异常均返回 HTTP 200 状态码,通过响应体 <code>code</code> 字段区分业务成功(0)与失败(1/401/403/404/422)。前端统一按 <code>code</code> 判断,无需处理 HTTP 状态码差异。</p></div><h2 id="总结" tabindex="-1">总结 <a class="header-anchor" href="#总结" aria-label="Permalink to &quot;总结&quot;">​</a></h2><p>一个 API 请求从浏览器到数据库经过 7 个阶段、15+ 个处理节点。中间件链负责横切关注点(认证、权限、租户、日志),控制器层负责参数获取和响应返回,逻辑层负责业务处理和数据加工,模型层负责数据库操作。这种分层设计使得每一层职责单一、可独立测试。</p></div></div></main><footer class="VPDocFooter" data-v-e6f2a212 data-v-1bcd8184><!--[--><!--]--><div class="edit-info" data-v-1bcd8184><div class="edit-link" data-v-1bcd8184><a class="VPLink link vp-external-link-icon no-icon edit-link-button" href="https://gitee.com/rxthinkcmf/RXThinkCMF_ThinkPhp8_NaiveVue" target="_blank" rel="noreferrer" data-v-1bcd8184><!--[--><span class="vpi-square-pen edit-link-icon" data-v-1bcd8184></span> 对本页提出修改建议<!--]--></a></div><!----></div><nav class="prev-next" aria-labelledby="doc-footer-aria-label" data-v-1bcd8184><span class="visually-hidden" id="doc-footer-aria-label" data-v-1bcd8184>Pager</span><div class="pager" data-v-1bcd8184><a class="VPLink link pager-link prev" href="/zh/architecture/overview.html" data-v-1bcd8184><!--[--><span class="desc" data-v-1bcd8184>上一页</span><span class="title" data-v-1bcd8184>4.1 整体架构概览</span><!--]--></a></div><div class="pager" data-v-1bcd8184><a class="VPLink link pager-link next" href="/zh/architecture/backend-layer.html" data-v-1bcd8184><!--[--><span class="desc" data-v-1bcd8184>下一页</span><span class="title" data-v-1bcd8184>4.3 后端分层架构</span><!--]--></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><footer class="VPFooter has-sidebar" data-v-d8b57b2d data-v-566314d4><div class="container" data-v-566314d4><p class="message" data-v-566314d4>小蚂蚁云团队 · 提供技术支持</p><p class="copyright" data-v-566314d4>Copyright © 2018~2026 www.rxthink.cn. All rights reserved.</p></div></footer><!--[--><!--]--></div></div>
<script>window.__VP_HASH_MAP__=JSON.parse("{\"404.md\":\"DnXdkDqR\",\"index.md\":\"DwKmi-4G\",\"readme.md\":\"Dc96kdRW\",\"zh_api-spec_dict-api.md\":\"NUiuUSlq\",\"zh_api-spec_error-code.md\":\"CQ4T4ZFZ\",\"zh_api-spec_overview.md\":\"CK-OeLss\",\"zh_api-spec_pagination.md\":\"Bo7Ef76-\",\"zh_api-spec_response.md\":\"Bk-AaRct\",\"zh_api-spec_token.md\":\"jMkJ5xgQ\",\"zh_api-spec_upload.md\":\"ChSSxCN7\",\"zh_appendix_api-cheatsheet.md\":\"D87VO31-\",\"zh_appendix_components.md\":\"fyJ7jrzR\",\"zh_appendix_config-reference.md\":\"B6EqUS-b\",\"zh_appendix_database-tables.md\":\"DKTMWuOe\",\"zh_appendix_enums.md\":\"CkvyY7GT\",\"zh_appendix_faq.md\":\"COwfiwYP\",\"zh_appendix_functions.md\":\"CGQtr08x\",\"zh_appendix_glossary.md\":\"J0bEzd0I\",\"zh_appendix_middleware.md\":\"CmbJWEbW\",\"zh_appendix_stores.md\":\"Dh_hF39k\",\"zh_architecture_backend-layer.md\":\"BZ5R8HPk\",\"zh_architecture_base-classes.md\":\"uc2FGZ_j\",\"zh_architecture_cache.md\":\"BOw_8G_U\",\"zh_architecture_cross-cutting.md\":\"vc1kRYiE\",\"zh_architecture_database-design.md\":\"BzfgR92I\",\"zh_architecture_directory-design.md\":\"BM2YdUmT\",\"zh_architecture_extensibility.md\":\"QZ84R2i9\",\"zh_architecture_frontend-layer.md\":\"BTDgI7w-\",\"zh_architecture_overview.md\":\"BnaVTCi_\",\"zh_architecture_request-flow.md\":\"D0BsQMGR\",\"zh_architecture_security.md\":\"Iqt-Ebwd\",\"zh_changelog.md\":\"Drokr7z3\",\"zh_core_attributes.md\":\"DeNMX0Z4\",\"zh_core_auth-flow.md\":\"BThny9jG\",\"zh_core_captcha.md\":\"CUOr7Tra\",\"zh_core_config.md\":\"BaqCBguN\",\"zh_core_cors.md\":\"Dh5Ib53O\",\"zh_core_data-scope.md\":\"BOydYtLz\",\"zh_core_demo-mode.md\":\"CqKw8Jyv\",\"zh_core_dict-guide.md\":\"DvZUKnNa\",\"zh_core_dict.md\":\"CxbQP8i-\",\"zh_core_exception.md\":\"BUYcfedi\",\"zh_core_idempotent.md\":\"nD_czH0E\",\"zh_core_jwt.md\":\"D2TavJa5\",\"zh_core_login-log.md\":\"Dmm4xVWZ\",\"zh_core_operation-log.md\":\"DiMhJXDh\",\"zh_core_param.md\":\"BL-GPRt2\",\"zh_core_password.md\":\"WTfXkxK9\",\"zh_core_rbac.md\":\"DOL5F3cl\",\"zh_core_tenant.md\":\"CQg_N2UO\",\"zh_course.md\":\"Cph30bJQ\",\"zh_deploy_backend.md\":\"CU8XNhiE\",\"zh_deploy_backup.md\":\"Bf8X87lY\",\"zh_deploy_checklist.md\":\"BrBUbhj_\",\"zh_deploy_ci-cd.md\":\"BRWcT7CB\",\"zh_deploy_db-migrate.md\":\"Bt5W_64F\",\"zh_deploy_docker.md\":\"BOaY2fag\",\"zh_deploy_env-plan.md\":\"DRKpus9J\",\"zh_deploy_frontend.md\":\"BrGHU1F8\",\"zh_deploy_performance.md\":\"DRGl6LxH\",\"zh_deploy_security.md\":\"CJ8IPLiZ\",\"zh_deploy_troubleshooting.md\":\"BlTG-JyI\",\"zh_directory.md\":\"Qt8gqC8l\",\"zh_faq.md\":\"BYKIm3Ca\",\"zh_frontend_api-module.md\":\"CnTYnrH5\",\"zh_frontend_directory.md\":\"BUirGLbE\",\"zh_frontend_display-components.md\":\"C68WbxFR\",\"zh_frontend_env-config.md\":\"DzzZ83kk\",\"zh_frontend_excel-components.md\":\"CD_Qzpi8\",\"zh_frontend_form-components.md\":\"Bnvr8f9n\",\"zh_frontend_http.md\":\"BSE1Sv4o\",\"zh_frontend_i18n.md\":\"DUs0JKIN\",\"zh_frontend_layout.md\":\"Dh0nlAcl\",\"zh_frontend_login.md\":\"C_-duo1r\",\"zh_frontend_new-page.md\":\"DkxO_HHk\",\"zh_frontend_overview.md\":\"D9Xb2BBe\",\"zh_frontend_permission.md\":\"Cq5kb5Ze\",\"zh_frontend_router.md\":\"D8QFo_kK\",\"zh_frontend_store.md\":\"z9sk_Uwh\",\"zh_frontend_style.md\":\"ztz67v8q\",\"zh_frontend_utils.md\":\"DhHK_RMH\",\"zh_generator_cli.md\":\"Dwtxs8pc\",\"zh_generator_code-engine.md\":\"D1FCDohb\",\"zh_generator_config.md\":\"BmLwY9ZN\",\"zh_generator_demo.md\":\"Bl9RCUrJ\",\"zh_generator_faq.md\":\"Byk-CMbK\",\"zh_generator_overview.md\":\"YUs40sI_\",\"zh_generator_parser.md\":\"m1nglXOp\",\"zh_generator_templates.md\":\"CtSA1kb0\",\"zh_generator_web-ui.md\":\"C9039zMB\",\"zh_guide_code-list.md\":\"JJTI-waS\",\"zh_guide_controller.md\":\"B3mcOAa-\",\"zh_guide_database.md\":\"DjsE5XOJ\",\"zh_guide_faq.md\":\"CCrcIy_p\",\"zh_guide_frontend-integration.md\":\"B12Frb9q\",\"zh_guide_logic.md\":\"B_PfGiwh\",\"zh_guide_model.md\":\"DHkU7EAm\",\"zh_guide_overview.md\":\"C5OyGWBL\",\"zh_guide_permission.md\":\"bjP9Fqiv\",\"zh_guide_route.md\":\"UZ6FkdKT\",\"zh_guide_validator.md\":\"BkbaSS6W\",\"zh_introduction.md\":\"DMqVN1Wj\",\"zh_modules_article.md\":\"BXsydoGy\",\"zh_modules_category.md\":\"B5Gj7rN0\",\"zh_modules_city.md\":\"BhtDw6n8\",\"zh_modules_content.md\":\"BuvJMAXR\",\"zh_modules_dept.md\":\"CGqctAiD\",\"zh_modules_filetemplate.md\":\"kWi6iDKt\",\"zh_modules_index.md\":\"DvKrh8b3\",\"zh_modules_job.md\":\"CAG6vctw\",\"zh_modules_level.md\":\"DBxSBy0k\",\"zh_modules_menu.md\":\"DWuKGLC2\",\"zh_modules_param.md\":\"_zgPjMmj\",\"zh_modules_position.md\":\"B_57MtnP\",\"zh_modules_role.md\":\"CIbbOvQn\",\"zh_modules_tenant.md\":\"DqsIRMEg\",\"zh_modules_user.md\":\"oiyHINGQ\",\"zh_other_contributing.md\":\"jQgDHTkE\",\"zh_other_declare.md\":\"DcbcZmrU\",\"zh_other_sponsor.md\":\"ATS7Udz-\",\"zh_quickstart_backend-start.md\":\"gv0vih9k\",\"zh_quickstart_database-init.md\":\"D5I5-rMl\",\"zh_quickstart_docker.md\":\"CrDzzKL8\",\"zh_quickstart_env-vars.md\":\"C6Sd8A2w\",\"zh_quickstart_environment.md\":\"DjDv4deJ\",\"zh_quickstart_faq.md\":\"DpjVbUSP\",\"zh_quickstart_first-api.md\":\"C3sEiyn-\",\"zh_quickstart_frontend-start.md\":\"CQn1XT_x\",\"zh_standards_api-response.md\":\"Di-uTKI6\",\"zh_standards_backend-code.md\":\"d2uVUR0z\",\"zh_standards_code-review.md\":\"DjZ5o7Ff\",\"zh_standards_deletion.md\":\"QmZTglzc\",\"zh_standards_frontend-code.md\":\"BUh8hNLV\",\"zh_standards_git.md\":\"DmaSsCtY\",\"zh_standards_pagination.md\":\"C-ZXANxf\",\"zh_tech-stack.md\":\"ITO2y2Rd\",\"zh_tools_db-migrate.md\":\"CPk-22lX\",\"zh_tools_excel.md\":\"xC3i8gqs\",\"zh_tools_file-components.md\":\"BcyIWLMs\",\"zh_tools_rich-text.md\":\"Gjwkfhnl\",\"zh_tools_upload-config.md\":\"BAIrAcEW\",\"zh_tools_upload.md\":\"Bum_cMj_\",\"zh_why.md\":\"tZMPA-kP\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"小蚂蚁云\",\"titleTemplate\":\"RXThinkCMF 开发文档\",\"description\":\"A VitePress site\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":\"light\",\"themeConfig\":{\"logo\":\"/logo.svg\",\"outline\":[2,3],\"socialLinks\":[{\"icon\":\"github\",\"link\":\"https://gitee.com/rxthinkcmf/RXThinkCMF_ThinkPhp8_NaiveVue\"}],\"footer\":{\"copyright\":\"Copyright © 2018~2026 www.rxthink.cn. All rights reserved.\",\"message\":\"小蚂蚁云团队 · 提供技术支持\"},\"editLink\":{\"pattern\":\"https://gitee.com/rxthinkcmf/RXThinkCMF_ThinkPhp8_NaiveVue\",\"text\":\"对本页提出修改建议\"},\"search\":{\"provider\":\"local\"}},\"locales\":{\"root\":{\"label\":\"简体中文\",\"lang\":\"zh-CN\",\"link\":\"/\",\"description\":\"RXThinkCMF 企业级前后端分离后台管理系统 - ThinkPHP8 + Vue3 + NaiveUI\",\"head\":[[\"meta\",{\"property\":\"og:url\",\"content\":\"http://docs.thinkphp8.naivevue.rxthink.cn\"}],[\"meta\",{\"property\":\"og:description\",\"content\":\"RXThinkCMF 企业级前后端分离后台管理系统 - ThinkPHP8 + Vue3 + NaiveUI\"}],[\"meta\",{\"property\":\"twitter:url\",\"content\":\"http://docs.thinkphp8.naivevue.rxthink.cn\"}],[\"meta\",{\"property\":\"twitter:title\",\"content\":\"RXThinkCMF ThinkPHP8+NaiveUI 开发文档\"}],[\"meta\",{\"property\":\"twitter:description\",\"content\":\"RXThinkCMF 企业级前后端分离后台管理系统 - ThinkPHP8 + Vue3 + NaiveUI\"}],[\"script\",{},\"\\n var _hmt = _hmt || [];\\n (function() {\\n var hm = document.createElement(\\\"script\\\");\\n hm.src = \\\"https://hm.baidu.com/hm.js?0c49c7c3cd09fbcaaf60dc5e5c8ff6e7\\\";\\n var s = document.getElementsByTagName(\\\"script\\\")[0];\\n s.parentNode.insertBefore(hm, s);\\n })();\\n \"]],\"themeConfig\":{\"editLink\":{\"pattern\":\"https://gitee.com/rxthinkcmf/RXThinkCMF_ThinkPhp8_NaiveVue\",\"text\":\"对本页提出修改建议\"},\"outline\":{\"label\":\"本页内容\"},\"docFooter\":{\"prev\":\"上一页\",\"next\":\"下一页\"},\"nav\":[{\"text\":\"官网\",\"link\":\"https://www.rxthink.cn\"},{\"text\":\"授权\",\"link\":\"https://www.rxthink.cn/goods/detail/2\"},{\"text\":\"部署文档\",\"items\":[{\"text\":\"RXThinkCMF混编版ThinkPHP6+Layui版本\",\"link\":\"http://docs.thinkphp6.layui.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离ThinkPHP6+ElementPlus版本\",\"link\":\"http://docs.thinkphp6.elevue.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离ThinkPHP6+AntDesign版本\",\"link\":\"http://docs.thinkphp6.antdvue.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离ThinkPHP6+NaiveUI版本\",\"link\":\"http://docs.thinkphp6.naivevue.rxthink.cn\"},{\"text\":\"RXThinkCMF混编版ThinkPHP8+Layui版本\",\"link\":\"http://docs.thinkphp8.layui.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离ThinkPHP8+ElementPlus版本\",\"link\":\"http://docs.thinkphp8.elevue.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离ThinkPHP8+AntDesign版本\",\"link\":\"http://docs.thinkphp8.antdvue.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离ThinkPHP8+NaiveUI版本\",\"link\":\"http://docs.thinkphp8.naivevue.rxthink.cn\"},{\"text\":\"RXThinkCMF混编版Laravel13+Layui版本\",\"link\":\"http://docs.laravel13.layui.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离Laravel13+ElementPlus版本\",\"link\":\"http://docs.laravel13.elevue.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离Laravel13+AntDesign版本\",\"link\":\"http://docs.laravel13.antdvue.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离Laravel13+NaiveUI版本\",\"link\":\"http://docs.laravel13.naivevue.rxthink.cn\"}]},{\"text\":\"在线演示\",\"items\":[{\"text\":\"RXThinkCMF混编版ThinkPHP6+Layui版本\",\"link\":\"http://manage.thinkphp6.layui.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离ThinkPHP6+ElementPlus版本\",\"link\":\"http://manage.thinkphp6.elevue.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离ThinkPHP6+AntDesign版本\",\"link\":\"http://manage.thinkphp6.antdvue.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离ThinkPHP6+NaiveUI版本\",\"link\":\"http://manage.thinkphp6.naivevue.rxthink.cn\"},{\"text\":\"RXThinkCMF混编版ThinkPHP8+Layui版本\",\"link\":\"http://manage.thinkphp8.layui.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离ThinkPHP8+ElementPlus版本\",\"link\":\"http://manage.thinkphp8.elevue.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离ThinkPHP8+AntDesign版本\",\"link\":\"http://manage.thinkphp8.antdvue.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离ThinkPHP8+NaiveUI版本\",\"link\":\"http://manage.thinkphp8.naivevue.rxthink.cn\"},{\"text\":\"RXThinkCMF混编版Laravel13+Layui版本\",\"link\":\"http://manage.laravel13.layui.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离Laravel13+ElementPlus版本\",\"link\":\"http://manage.laravel13.elevue.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离Laravel13+AntDesign版本\",\"link\":\"http://manage.laravel13.antdvue.rxthink.cn\"},{\"text\":\"RXThinkCMF前后端分离Laravel13+NaiveUI版本\",\"link\":\"http://manage.laravel13.naivevue.rxthink.cn\"}]},{\"text\":\"广告赞助\",\"link\":\"/zh/other/sponsor.html\"},{\"text\":\"相关链接\",\"items\":[{\"text\":\"官方网站\",\"link\":\"https://www.rxthink.cn\"},{\"text\":\"Gitee 仓库\",\"link\":\"https://gitee.com/rxthinkcmf/RXThinkCMF_ThinkPhp8_NaiveVue\"},{\"text\":\"ThinkPHP 官网\",\"link\":\"https://www.thinkphp.cn/\"},{\"text\":\"Vue3 文档\",\"link\":\"https://cn.vuejs.org/\"},{\"text\":\"NaiveUI\",\"link\":\"https://www.naiveui.com/\"}]}],\"sidebar\":{\"/zh/\":[{\"text\":\"📖 1. 了解项目\",\"collapsed\":false,\"items\":[{\"text\":\"1.1 项目介绍\",\"link\":\"/zh/introduction.html\"},{\"text\":\"1.2 为什么选择我们\",\"link\":\"/zh/why.html\"},{\"text\":\"1.3 项目目录结构\",\"link\":\"/zh/directory.html\"},{\"text\":\"1.4 新手入门指南\",\"link\":\"/zh/course.html\"},{\"text\":\"1.5 技术栈说明\",\"link\":\"/zh/tech-stack.html\"},{\"text\":\"1.6 更新日志\",\"link\":\"/zh/changelog.html\"}]},{\"text\":\"🚀 2. 快速入门\",\"collapsed\":false,\"items\":[{\"text\":\"2.1 开发环境准备\",\"link\":\"/zh/quickstart/environment.html\"},{\"text\":\"2.2 后端服务启动\",\"link\":\"/zh/quickstart/backend-start.html\"},{\"text\":\"2.3 前端服务启动\",\"link\":\"/zh/quickstart/frontend-start.html\"},{\"text\":\"2.4 数据库初始化\",\"link\":\"/zh/quickstart/database-init.html\"},{\"text\":\"2.5 环境变量配置\",\"link\":\"/zh/quickstart/env-vars.html\"},{\"text\":\"2.6 第一个接口调试\",\"link\":\"/zh/quickstart/first-api.html\"},{\"text\":\"2.7 Docker 快速体验\",\"link\":\"/zh/quickstart/docker.html\"},{\"text\":\"2.8 常见问题 FAQ\",\"link\":\"/zh/quickstart/faq.html\"}]},{\"text\":\"🧪 3. 模块开发实战\",\"collapsed\":false,\"items\":[{\"text\":\"3.1 概述与目标\",\"link\":\"/zh/guide/overview.html\"},{\"text\":\"3.2 数据库建表\",\"link\":\"/zh/guide/database.html\"},{\"text\":\"3.3 模型层开发\",\"link\":\"/zh/guide/model.html\"},{\"text\":\"3.4 验证器开发\",\"link\":\"/zh/guide/validator.html\"},{\"text\":\"3.5 逻辑层开发\",\"link\":\"/zh/guide/logic.html\"},{\"text\":\"3.6 控制器开发\",\"link\":\"/zh/guide/controller.html\"},{\"text\":\"3.7 路由注册\",\"link\":\"/zh/guide/route.html\"},{\"text\":\"3.8 权限节点配置\",\"link\":\"/zh/guide/permission.html\"},{\"text\":\"3.9 前端联调指引\",\"link\":\"/zh/guide/frontend-integration.html\"},{\"text\":\"3.10 完整代码清单\",\"link\":\"/zh/guide/code-list.html\"},{\"text\":\"3.11 常见问题与排错\",\"link\":\"/zh/guide/faq.html\"}]},{\"text\":\"🏛️ 4. 架构设计\",\"collapsed\":false,\"items\":[{\"text\":\"4.1 整体架构概览\",\"link\":\"/zh/architecture/overview.html\"},{\"text\":\"4.2 请求处理链路\",\"link\":\"/zh/architecture/request-flow.html\"},{\"text\":\"4.3 后端分层架构\",\"link\":\"/zh/architecture/backend-layer.html\"},{\"text\":\"4.4 前端分层架构\",\"link\":\"/zh/architecture/frontend-layer.html\"},{\"text\":\"4.5 目录结构设计\",\"link\":\"/zh/architecture/directory-design.html\"},{\"text\":\"4.6 核心基类体系\",\"link\":\"/zh/architecture/base-classes.html\"},{\"text\":\"4.7 横切机制\",\"link\":\"/zh/architecture/cross-cutting.html\"},{\"text\":\"4.8 缓存架构设计\",\"link\":\"/zh/architecture/cache.html\"},{\"text\":\"4.9 数据库设计\",\"link\":\"/zh/architecture/database-design.html\"},{\"text\":\"4.10 安全架构设计\",\"link\":\"/zh/architecture/security.html\"},{\"text\":\"4.11 扩展性设计\",\"link\":\"/zh/architecture/extensibility.html\"}]},{\"text\":\"🔐 5. 核心功能\",\"collapsed\":false,\"items\":[{\"text\":\"认证与安全\",\"collapsed\":false,\"items\":[{\"text\":\"5.1 用户认证(JWT)\",\"link\":\"/zh/core/jwt.html\"},{\"text\":\"5.2 认证流程实战\",\"link\":\"/zh/core/auth-flow.html\"},{\"text\":\"5.3 验证码机制\",\"link\":\"/zh/core/captcha.html\"},{\"text\":\"5.4 权限管理(RBAC)\",\"link\":\"/zh/core/rbac.html\"},{\"text\":\"5.5 跨域资源共享\",\"link\":\"/zh/core/cors.html\"},{\"text\":\"5.6 密码加密服务\",\"link\":\"/zh/core/password.html\"},{\"text\":\"5.7 演示模式\",\"link\":\"/zh/core/demo-mode.html\"}]},{\"text\":\"数据与配置\",\"collapsed\":false,\"items\":[{\"text\":\"5.8 多租户隔离\",\"link\":\"/zh/core/tenant.html\"},{\"text\":\"5.9 数据权限\",\"link\":\"/zh/core/data-scope.html\"},{\"text\":\"5.10 字典模块\",\"link\":\"/zh/core/dict.html\"},{\"text\":\"5.11 字典配置与使用\",\"link\":\"/zh/core/dict-guide.html\"},{\"text\":\"5.12 系统配置管理\",\"link\":\"/zh/core/config.html\"},{\"text\":\"5.13 系统参数管理\",\"link\":\"/zh/core/param.html\"}]},{\"text\":\"日志与监控\",\"collapsed\":false,\"items\":[{\"text\":\"5.14 操作日志\",\"link\":\"/zh/core/operation-log.html\"},{\"text\":\"5.15 登录日志\",\"link\":\"/zh/core/login-log.html\"},{\"text\":\"5.16 异常与响应处理\",\"link\":\"/zh/core/exception.html\"}]},{\"text\":\"防护与治理\",\"collapsed\":false,\"items\":[{\"text\":\"5.17 防重复提交\",\"link\":\"/zh/core/idempotent.html\"}]},{\"text\":\"注解系统\",\"collapsed\":false,\"items\":[{\"text\":\"5.18 注解系统总览\",\"link\":\"/zh/core/attributes.html\"}]}]},{\"text\":\"📦 6. 业务模块\",\"collapsed\":false,\"items\":[{\"text\":\"6.1 用户管理\",\"link\":\"/zh/modules/user.html\"},{\"text\":\"6.2 角色管理\",\"link\":\"/zh/modules/role.html\"},{\"text\":\"6.3 菜单管理\",\"link\":\"/zh/modules/menu.html\"},{\"text\":\"6.4 部门管理\",\"link\":\"/zh/modules/dept.html\"},{\"text\":\"6.5 职级管理\",\"link\":\"/zh/modules/level.html\"},{\"text\":\"6.6 岗位管理\",\"link\":\"/zh/modules/position.html\"},{\"text\":\"6.7 文章管理\",\"link\":\"/zh/modules/article.html\"},{\"text\":\"6.8 公告与链接管理\",\"link\":\"/zh/modules/content.html\"},{\"text\":\"6.9 行政区划管理\",\"link\":\"/zh/modules/city.html\"},{\"text\":\"6.10 分类管理\",\"link\":\"/zh/modules/category.html\"},{\"text\":\"6.11 定时任务\",\"link\":\"/zh/modules/job.html\"},{\"text\":\"6.12 参数管理\",\"link\":\"/zh/modules/param.html\"},{\"text\":\"6.13 租户管理\",\"link\":\"/zh/modules/tenant.html\"},{\"text\":\"6.14 文件模板管理\",\"link\":\"/zh/modules/filetemplate.html\"},{\"text\":\"6.15 首页与个人中心\",\"link\":\"/zh/modules/index.html\"}]},{\"text\":\"🧰 7. 文件处理\",\"collapsed\":false,\"items\":[{\"text\":\"7.1 文件上传全流程\",\"link\":\"/zh/tools/upload.html\"},{\"text\":\"7.2 上传配置详解\",\"link\":\"/zh/tools/upload-config.html\"},{\"text\":\"7.3 富文本处理\",\"link\":\"/zh/tools/rich-text.html\"},{\"text\":\"7.4 数据导入导出\",\"link\":\"/zh/tools/excel.html\"},{\"text\":\"7.5 前端文件组件\",\"link\":\"/zh/tools/file-components.html\"},{\"text\":\"7.6 数据库迁移工具\",\"link\":\"/zh/tools/db-migrate.html\"}]},{\"text\":\"🔗 8. 接口规范与对接\",\"collapsed\":false,\"items\":[{\"text\":\"8.1 统一响应格式\",\"link\":\"/zh/api-spec/response.html\"},{\"text\":\"8.2 错误码对照表\",\"link\":\"/zh/api-spec/error-code.html\"},{\"text\":\"8.3 分页查询规范\",\"link\":\"/zh/api-spec/pagination.html\"},{\"text\":\"8.4 文件上传接口\",\"link\":\"/zh/api-spec/upload.html\"},{\"text\":\"8.5 字典数据接口\",\"link\":\"/zh/api-spec/dict-api.html\"},{\"text\":\"8.6 Token 使用说明\",\"link\":\"/zh/api-spec/token.html\"},{\"text\":\"8.7 API 接口总览\",\"link\":\"/zh/api-spec/overview.html\"}]},{\"text\":\"🖥️ 9. 前端开发\",\"collapsed\":false,\"items\":[{\"text\":\"工程基础\",\"collapsed\":false,\"items\":[{\"text\":\"9.1 前端工程概述\",\"link\":\"/zh/frontend/overview.html\"},{\"text\":\"9.2 目录结构详解\",\"link\":\"/zh/frontend/directory.html\"},{\"text\":\"9.3 环境与构建配置\",\"link\":\"/zh/frontend/env-config.html\"}]},{\"text\":\"核心机制\",\"collapsed\":false,\"items\":[{\"text\":\"9.4 HTTP 请求封装\",\"link\":\"/zh/frontend/http.html\"},{\"text\":\"9.5 路由与动态菜单\",\"link\":\"/zh/frontend/router.html\"},{\"text\":\"9.6 状态管理(Pinia)\",\"link\":\"/zh/frontend/store.html\"},{\"text\":\"9.7 权限控制\",\"link\":\"/zh/frontend/permission.html\"},{\"text\":\"9.8 登录流程\",\"link\":\"/zh/frontend/login.html\"}]},{\"text\":\"公共组件\",\"collapsed\":false,\"items\":[{\"text\":\"9.9 数据展示组件\",\"link\":\"/zh/frontend/display-components.html\"},{\"text\":\"9.10 数据录入组件\",\"link\":\"/zh/frontend/form-components.html\"},{\"text\":\"9.11 Excel 导入导出组件\",\"link\":\"/zh/frontend/excel-components.html\"}]},{\"text\":\"开发实践\",\"collapsed\":false,\"items\":[{\"text\":\"9.12 新增页面开发步骤\",\"link\":\"/zh/frontend/new-page.html\"},{\"text\":\"9.13 API 模块编写规范\",\"link\":\"/zh/frontend/api-module.html\"},{\"text\":\"9.14 样式与主题定制\",\"link\":\"/zh/frontend/style.html\"},{\"text\":\"9.15 布局系统\",\"link\":\"/zh/frontend/layout.html\"},{\"text\":\"9.16 工具函数\",\"link\":\"/zh/frontend/utils.html\"},{\"text\":\"9.17 国际化(i18n)\",\"link\":\"/zh/frontend/i18n.html\"}]}]},{\"text\":\"🔧 10. 代码生成器\",\"collapsed\":false,\"items\":[{\"text\":\"10.1 概述与架构\",\"link\":\"/zh/generator/overview.html\"},{\"text\":\"10.2 CLI 命令行使用\",\"link\":\"/zh/generator/cli.html\"},{\"text\":\"10.3 Web 管理界面\",\"link\":\"/zh/generator/web-ui.html\"},{\"text\":\"10.4 表结构解析引擎\",\"link\":\"/zh/generator/parser.html\"},{\"text\":\"10.5 代码生成引擎\",\"link\":\"/zh/generator/code-engine.html\"},{\"text\":\"10.6 自定义模板开发\",\"link\":\"/zh/generator/templates.html\"},{\"text\":\"10.7 配置文件详解\",\"link\":\"/zh/generator/config.html\"},{\"text\":\"10.8 实战案例\",\"link\":\"/zh/generator/demo.html\"},{\"text\":\"10.9 常见问题\",\"link\":\"/zh/generator/faq.html\"}]},{\"text\":\"⚙️ 11. 运维部署\",\"collapsed\":false,\"items\":[{\"text\":\"11.1 部署 Checklist\",\"link\":\"/zh/deploy/checklist.html\"},{\"text\":\"11.2 环境规划\",\"link\":\"/zh/deploy/env-plan.html\"},{\"text\":\"11.3 数据库迁移\",\"link\":\"/zh/deploy/db-migrate.html\"},{\"text\":\"11.4 后端部署\",\"link\":\"/zh/deploy/backend.html\"},{\"text\":\"11.5 前端部署\",\"link\":\"/zh/deploy/frontend.html\"},{\"text\":\"11.6 Docker 生产部署\",\"link\":\"/zh/deploy/docker.html\"},{\"text\":\"11.7 性能调优\",\"link\":\"/zh/deploy/performance.html\"},{\"text\":\"11.8 安全加固清单\",\"link\":\"/zh/deploy/security.html\"},{\"text\":\"11.9 备份与恢复\",\"link\":\"/zh/deploy/backup.html\"},{\"text\":\"11.10 故障排查手册\",\"link\":\"/zh/deploy/troubleshooting.html\"},{\"text\":\"11.11 CI/CD 流水线\",\"link\":\"/zh/deploy/ci-cd.html\"}]},{\"text\":\"📋 12. 规范标准\",\"collapsed\":false,\"items\":[{\"text\":\"⭐ 必须遵守\",\"collapsed\":false,\"items\":[{\"text\":\"12.1 API 响应规范\",\"link\":\"/zh/standards/api-response.html\"},{\"text\":\"12.2 分页查询规范\",\"link\":\"/zh/standards/pagination.html\"},{\"text\":\"12.3 Git 提交规范\",\"link\":\"/zh/standards/git.html\"}]},{\"text\":\"📌 建议遵守\",\"collapsed\":false,\"items\":[{\"text\":\"12.4 数据删除规范\",\"link\":\"/zh/standards/deletion.html\"},{\"text\":\"12.5 代码审查清单\",\"link\":\"/zh/standards/code-review.html\"},{\"text\":\"12.6 后端编码规范\",\"link\":\"/zh/standards/backend-code.html\"},{\"text\":\"12.7 前端编码规范\",\"link\":\"/zh/standards/frontend-code.html\"}]}]},{\"text\":\"📄 附录\",\"collapsed\":false,\"items\":[{\"text\":\"A. 常见问题汇总\",\"link\":\"/zh/appendix/faq.html\"},{\"text\":\"B. 数据库表结构速查\",\"link\":\"/zh/appendix/database-tables.html\"},{\"text\":\"C. 配置项速查\",\"link\":\"/zh/appendix/config-reference.html\"},{\"text\":\"D. 公共函数速查\",\"link\":\"/zh/appendix/functions.html\"},{\"text\":\"E. API 接口速查表\",\"link\":\"/zh/appendix/api-cheatsheet.html\"},{\"text\":\"F. 中间件执行顺序\",\"link\":\"/zh/appendix/middleware.html\"},{\"text\":\"G. 前端组件速查\",\"link\":\"/zh/appendix/components.html\"},{\"text\":\"H. 前端 Store 速查\",\"link\":\"/zh/appendix/stores.html\"},{\"text\":\"I. 前端 Enums 速查\",\"link\":\"/zh/appendix/enums.html\"},{\"text\":\"J. 术语表\",\"link\":\"/zh/appendix/glossary.html\"},{\"text\":\"K. 贡献指南\",\"link\":\"/zh/other/contributing.html\"},{\"text\":\"L. 免责声明\",\"link\":\"/zh/other/declare.html\"},{\"text\":\"M. 广告赞助\",\"link\":\"/zh/other/sponsor.html\"},{\"text\":\"N. 开源协议\",\"link\":\"https://gitee.com/rxthinkcmf/RXThinkCMF_ThinkPhp8_NaiveVue\"}]}]}}}},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
</body>
</html>