400 lines
232 KiB
HTML
400 lines
232 KiB
HTML
<!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 "4.2 请求处理链路""></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 "第一阶段:网络层""></a></h2><h3 id="_1-浏览器发起请求" tabindex="-1">1. 浏览器发起请求 <a class="header-anchor" href="#_1-浏览器发起请求" aria-label="Permalink to "1. 浏览器发起请求""></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">/example/add</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">POST</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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: '测试案例', 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 <JWT Token></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 "2. Nginx 反向代理(生产环境)""></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">/api</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">http://localhost:8000</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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 "第二阶段:路由解析""></a></h2><h3 id="_3-ThinkPHP-入口" tabindex="-1">3. ThinkPHP 入口 <a class="header-anchor" href="#_3-ThinkPHP-入口" aria-label="Permalink to "3. ThinkPHP 入口""></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 "4. 路由匹配""></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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">api</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">login</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">LoginController/login</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">captcha</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">LoginController/captcha</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">api</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">example</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">add</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">ExampleController/add</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">-></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 "第三阶段:中间件链(按顺序执行)""></a></h2><h3 id="_5-CorsMiddleware-全局中间件-" tabindex="-1">5. CorsMiddleware(全局中间件) <a class="header-anchor" href="#_5-CorsMiddleware-全局中间件-" aria-label="Permalink to "5. CorsMiddleware(全局中间件)""></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;">-></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;">''</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">html</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">-></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">Access-Control-Allow-Origin</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">origin</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
|
||
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">Access-Control-Allow-Methods</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">GET, POST, PUT, DELETE, PATCH, OPTIONS</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
|
||
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">Access-Control-Allow-Headers</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">Content-Type, Authorization, ...</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
|
||
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">Access-Control-Allow-Credentials</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">true</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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 "6. AuthMiddleware(JWT 认证 + 权限校验)""></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;">-></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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">未提供认证令牌</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">e</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-></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;">-></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;"> ''</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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">access</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">无效的认证令牌</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">-></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;">-></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;">-></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;">-></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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">无访问权限</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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 <token></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 === 'access'</span></span>
|
||
<span class="line"><span> │ └─ 不是 → 返回 401</span></span>
|
||
<span class="line"><span> │</span></span>
|
||
<span class="line"><span> ├─ 注入 $request->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 "7. TenantMiddleware(租户上下文)""></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;">-></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;">-></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;">-></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;">-></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;">-></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;"> ></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;">-></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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">租户已被禁用</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">-></span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">expire_time</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> &&</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;">-></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;"> <</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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">租户已过期</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">-></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->tenantId</code> — 租户 ID(0=超级管理员)</li><li><code>$request->isSuperAdmin</code> — 是否超级管理员</li><li><code>$request->tenantInfo</code> — 租户信息对象</li></ul><h3 id="_8-DemoMiddleware-演示环境拦截-" tabindex="-1">8. DemoMiddleware(演示环境拦截) <a class="header-anchor" href="#_8-DemoMiddleware-演示环境拦截-" aria-label="Permalink to "8. DemoMiddleware(演示环境拦截)""></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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">app_demo</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">-></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">GET</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">演示环境,禁止操作</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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 "9. LogMiddleware(操作日志)""></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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">POST</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">PUT</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">DELETE</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">PATCH</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">title</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">logAttr</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">?-></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">type</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">logAttr</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">?-></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;">-></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">method</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">method</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
|
||
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">url</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">request</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">param</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></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;">-></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">ip</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">requestInfo</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">location</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">requestInfo</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">os</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">requestInfo</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">browser</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">requestInfo</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">consume_time</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">=></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">status</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">-></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;">-></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 "第四阶段:控制器层""></a></h2><h3 id="_10-ExampleController-add-" tabindex="-1">10. ExampleController::add() <a class="header-anchor" href="#_10-ExampleController-add-" aria-label="Permalink to "10. ExampleController::add()""></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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">案例演示-新增记录</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">新增案例演示:{name}</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">sys:example:add</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">添加案例演示</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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->logic->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;">-></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;">-></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 "第五阶段:逻辑层""></a></h2><h3 id="_11-ExampleLogic-add-" tabindex="-1">11. ExampleLogic::add() <a class="header-anchor" href="#_11-ExampleLogic-add-" aria-label="Permalink to "11. ExampleLogic::add()""></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;">-></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;">-></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;">-></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;">-></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;">-></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;">-></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;">-></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;">-></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;">-></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;">-></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 "第六阶段:模型层""></a></h2><h3 id="_12-BaseModel-自动处理" tabindex="-1">12. BaseModel 自动处理 <a class="header-anchor" href="#_12-BaseModel-自动处理" aria-label="Permalink to "12. BaseModel 自动处理""></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">example</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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 "13. 数据库执行""></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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">测试案例</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">''</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">admin</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">2026-09-20 12:00:00</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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 "第七阶段:响应返回""></a></h2><h3 id="_14-响应序列化" tabindex="-1">14. 响应序列化 <a class="header-anchor" href="#_14-响应序列化" aria-label="Permalink to "14. 响应序列化""></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;">-></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;">-></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;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">id</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">id</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">],</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">添加成功</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">操作成功</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">code</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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 style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">ok</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></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;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">msg</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</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;">msg</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
|
||
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">data</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> =></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 "15. 浏览器接收响应""></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;"> "</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">code</span><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;">"</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;"> "</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">ok</span><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;">"</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;"> "</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">msg</span><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;">"</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> "</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">添加成功</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;"> "</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">data</span><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;">"</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;"> "</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">id</span><span style="--shiki-dark:#97E2F2;--shiki-light:#99841877;">"</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 "完整链路流程图""></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 <token></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 === 'access'</span></span>
|
||
<span class="line"><span> ├─ 注入 $request->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->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->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:"添加成功", 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 "异常处理链路""></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:"参数验证失败", data:{错误明细}}</code></td></tr><tr><td><code>ModelNotFoundException</code></td><td>数据不存在</td><td><code>{code:1, msg:"数据不存在"}</code></td></tr><tr><td><code>RuntimeException (401)</code></td><td>JWT 过期/无效</td><td><code>{code:1, msg:"token已过期"}</code></td></tr><tr><td><code>HttpException</code></td><td>HTTP 错误</td><td><code>{code:1, msg:"请求错误"}</code></td></tr><tr><td><code>Exception</code></td><td>未捕获异常</td><td><code>{code:1, msg:"操作失败"}</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 "总结""></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> |