[{"data":1,"prerenderedAt":4448},["ShallowReactive",2],{"article-/topics/next/parallel-sequential-data-fetching-guide":3,"related-next":751,"content-query-2vDW6STsSK":3868},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"topic":5,"author":11,"tags":12,"image":18,"imageQuery":19,"pexelsPhotoId":20,"pexelsUrl":21,"featured":6,"readingTime":22,"body":23,"_type":745,"_id":746,"_source":747,"_file":748,"_stem":749,"_extension":750},"/topics/next/parallel-sequential-data-fetching-guide","next",false,"","Next.js 并行与顺序数据获取指南：什么时候一起拉，什么时候分阶段等","讲清 Next.js App Router 中并行请求与顺序请求的差异、Suspense 拆分方式、瀑布请求成因与重构思路，帮助团队把数据获取从“能用”推进到“可预测、可扩展、可观测”。","2026-04-08","HTMLPAGE 团队",[13,14,15,16,17],"Next.js","App Router","Data Fetching","Suspense","Performance","/images/topics/next/parallel-sequential-data-fetching-guide.jpg","developer multiple monitors code laptop office",34804016,"https://www.pexels.com/photo/modern-workspace-with-laptop-and-code-display-34804016/",15,{"type":24,"children":25,"toc":731},"root",[26,34,57,62,66,72,77,181,186,189,195,200,212,217,226,246,249,255,260,265,285,290,295,304,309,312,318,330,339,344,363,368,371,377,382,405,410,415,433,438,456,459,465,470,569,574,577,583,588,599,604,622,627,630,636,681,684,690,695,700],{"type":27,"tag":28,"props":29,"children":31},"element","h2",{"id":30},"nextjs-并行与顺序数据获取指南什么时候一起拉什么时候分阶段等",[32],{"type":33,"value":8},"text",{"type":27,"tag":35,"props":36,"children":37},"p",{},[38,40,47,49,55],{"type":33,"value":39},"很多团队第一次迁到 App Router 时，会把“服务端组件能直接 ",{"type":27,"tag":41,"props":42,"children":44},"code",{"className":43},[],[45],{"type":33,"value":46},"await fetch",{"type":33,"value":48},"”理解成“以后看到数据就写一个 ",{"type":27,"tag":41,"props":50,"children":52},{"className":51},[],[53],{"type":33,"value":54},"await",{"type":33,"value":56},"”。页面当然能跑，但也很容易出现两个问题：首屏被慢接口拖死，或者组件层级一深就不知不觉形成瀑布请求。",{"type":27,"tag":35,"props":58,"children":59},{},[60],{"type":33,"value":61},"真正需要建立的不是 API 调用技巧，而是数据获取的决策模型：哪些请求应该并行发起，哪些必须顺序执行，哪些应该拆到独立的 Suspense 边界里，哪些应该提前在布局层准备好。",{"type":27,"tag":63,"props":64,"children":65},"hr",{},[],{"type":27,"tag":28,"props":67,"children":69},{"id":68},"_1-先建立判断标准依赖关系决定调度方式",[70],{"type":33,"value":71},"1. 先建立判断标准：依赖关系决定调度方式",{"type":27,"tag":35,"props":73,"children":74},{},[75],{"type":33,"value":76},"判断一个请求是并行还是顺序，不要先看代码写法，先看业务依赖。",{"type":27,"tag":78,"props":79,"children":80},"table",{},[81,105],{"type":27,"tag":82,"props":83,"children":84},"thead",{},[85],{"type":27,"tag":86,"props":87,"children":88},"tr",{},[89,95,100],{"type":27,"tag":90,"props":91,"children":92},"th",{},[93],{"type":33,"value":94},"场景",{"type":27,"tag":90,"props":96,"children":97},{},[98],{"type":33,"value":99},"推荐方式",{"type":27,"tag":90,"props":101,"children":102},{},[103],{"type":33,"value":104},"原因",{"type":27,"tag":106,"props":107,"children":108},"tbody",{},[109,128,146,164],{"type":27,"tag":86,"props":110,"children":111},{},[112,118,123],{"type":27,"tag":113,"props":114,"children":115},"td",{},[116],{"type":33,"value":117},"用户信息、公告、导航配置互不依赖",{"type":27,"tag":113,"props":119,"children":120},{},[121],{"type":33,"value":122},"并行",{"type":27,"tag":113,"props":124,"children":125},{},[126],{"type":33,"value":127},"谁慢都不该阻塞其他数据",{"type":27,"tag":86,"props":129,"children":130},{},[131,136,141],{"type":27,"tag":113,"props":132,"children":133},{},[134],{"type":33,"value":135},"先拿用户权限，再决定能不能请求订单数据",{"type":27,"tag":113,"props":137,"children":138},{},[139],{"type":33,"value":140},"顺序",{"type":27,"tag":113,"props":142,"children":143},{},[144],{"type":33,"value":145},"第二个请求依赖第一个结果",{"type":27,"tag":86,"props":147,"children":148},{},[149,154,159],{"type":27,"tag":113,"props":150,"children":151},{},[152],{"type":33,"value":153},"商品详情和推荐商品都能独立返回",{"type":27,"tag":113,"props":155,"children":156},{},[157],{"type":33,"value":158},"并行 + 分 Suspense",{"type":27,"tag":113,"props":160,"children":161},{},[162],{"type":33,"value":163},"详情优先可见，推荐可延后",{"type":27,"tag":86,"props":165,"children":166},{},[167,172,176],{"type":27,"tag":113,"props":168,"children":169},{},[170],{"type":33,"value":171},"先根据 slug 查文章，再根据文章 id 查相关推荐",{"type":27,"tag":113,"props":173,"children":174},{},[175],{"type":33,"value":140},{"type":27,"tag":113,"props":177,"children":178},{},[179],{"type":33,"value":180},"相关推荐需要文章 id",{"type":27,"tag":35,"props":182,"children":183},{},[184],{"type":33,"value":185},"一句话判断：如果 B 请求的参数、权限或业务分支依赖 A 的结果，就顺序；否则默认先考虑并行。",{"type":27,"tag":63,"props":187,"children":188},{},[],{"type":27,"tag":28,"props":190,"children":192},{"id":191},"_2-并行请求解决的是无意义等待",[193],{"type":33,"value":194},"2. 并行请求解决的是“无意义等待”",{"type":27,"tag":35,"props":196,"children":197},{},[198],{"type":33,"value":199},"在服务端组件里，最常见的低效写法是：",{"type":27,"tag":201,"props":202,"children":207},"pre",{"className":203,"code":205,"language":206,"meta":7},[204],"language-tsx","async function DashboardPage() {\n  const profile = await getProfile()\n  const notifications = await getNotifications()\n  const projects = await getProjects()\n\n  return \u003CDashboard profile={profile} notifications={notifications} projects={projects} />\n}\n","tsx",[208],{"type":27,"tag":41,"props":209,"children":210},{"__ignoreMap":7},[211],{"type":33,"value":205},{"type":27,"tag":35,"props":213,"children":214},{},[215],{"type":33,"value":216},"如果这三个请求彼此独立，那么总耗时接近三者之和。更合适的做法是尽快把请求都发出去：",{"type":27,"tag":201,"props":218,"children":221},{"className":219,"code":220,"language":206,"meta":7},[204],"async function DashboardPage() {\n  const profilePromise = getProfile()\n  const notificationsPromise = getNotifications()\n  const projectsPromise = getProjects()\n\n  const [profile, notifications, projects] = await Promise.all([\n    profilePromise,\n    notificationsPromise,\n    projectsPromise,\n  ])\n\n  return \u003CDashboard profile={profile} notifications={notifications} projects={projects} />\n}\n",[222],{"type":27,"tag":41,"props":223,"children":224},{"__ignoreMap":7},[225],{"type":33,"value":220},{"type":27,"tag":35,"props":227,"children":228},{},[229,231,237,239,244],{"type":33,"value":230},"这里真正重要的不是 ",{"type":27,"tag":41,"props":232,"children":234},{"className":233},[],[235],{"type":33,"value":236},"Promise.all",{"type":33,"value":238}," 本身，而是“请求尽早发起”。很多时候你甚至不需要立刻 ",{"type":27,"tag":41,"props":240,"children":242},{"className":241},[],[243],{"type":33,"value":54},{"type":33,"value":245},"，只要先创建 promise，再把等待放到更靠近渲染的位置。",{"type":27,"tag":63,"props":247,"children":248},{},[],{"type":27,"tag":28,"props":250,"children":252},{"id":251},"_3-顺序请求不是坏事关键是明确它为什么顺序",[253],{"type":33,"value":254},"3. 顺序请求不是坏事，关键是明确它为什么顺序",{"type":27,"tag":35,"props":256,"children":257},{},[258],{"type":33,"value":259},"有些团队会把所有顺序请求都视为性能问题，这也不对。顺序链路只要是由业务依赖驱动的，就是合理成本。",{"type":27,"tag":35,"props":261,"children":262},{},[263],{"type":33,"value":264},"例如：",{"type":27,"tag":266,"props":267,"children":268},"ol",{},[269,275,280],{"type":27,"tag":270,"props":271,"children":272},"li",{},[273],{"type":33,"value":274},"先验证当前用户有没有访问某组织空间的权限",{"type":27,"tag":270,"props":276,"children":277},{},[278],{"type":33,"value":279},"再按组织范围读取报表",{"type":27,"tag":270,"props":281,"children":282},{},[283],{"type":33,"value":284},"最后根据报表状态决定是否查询异常详情",{"type":27,"tag":35,"props":286,"children":287},{},[288],{"type":33,"value":289},"这类链路如果为了追求“并行”而把权限与业务数据一起拉，只会增加无效请求、暴露错误边界，甚至放大安全风险。",{"type":27,"tag":35,"props":291,"children":292},{},[293],{"type":33,"value":294},"更好的做法是把顺序依赖写清楚，让代码表达业务判断：",{"type":27,"tag":201,"props":296,"children":299},{"className":297,"code":298,"language":206,"meta":7},[204],"async function ReportsPage({ params }: { params: Promise\u003C{ orgId: string }> }) {\n  const { orgId } = await params\n  const viewer = await requireOrganizationMember(orgId)\n  const report = await getOrganizationReport(orgId, viewer.role)\n\n  return \u003CReportsView viewer={viewer} report={report} />\n}\n",[300],{"type":27,"tag":41,"props":301,"children":302},{"__ignoreMap":7},[303],{"type":33,"value":298},{"type":27,"tag":35,"props":305,"children":306},{},[307],{"type":33,"value":308},"如果顺序存在，就让它看起来像“有理由的流程”，而不是“随手往下写的 await”。",{"type":27,"tag":63,"props":310,"children":311},{},[],{"type":27,"tag":28,"props":313,"children":315},{"id":314},"_4-suspense-的价值不是炫技而是把等待拆开",[316],{"type":33,"value":317},"4. Suspense 的价值不是炫技，而是把等待拆开",{"type":27,"tag":35,"props":319,"children":320},{},[321,323,328],{"type":33,"value":322},"并行请求如果最后仍然在页面最上层统一 ",{"type":27,"tag":41,"props":324,"children":326},{"className":325},[],[327],{"type":33,"value":54},{"type":33,"value":329},"，用户不一定能感受到收益。真正能改善体验的是：主内容先出，次要内容在独立边界里补齐。",{"type":27,"tag":201,"props":331,"children":334},{"className":332,"code":333,"language":206,"meta":7},[204],"import { Suspense } from 'react'\n\nexport default async function ProductPage({ params }: { params: Promise\u003C{ slug: string }> }) {\n  const { slug } = await params\n  const productPromise = getProductBySlug(slug)\n  const recommendationsPromise = getRecommendations(slug)\n\n  return (\n    \u003C>\n      \u003CProductHero productPromise={productPromise} />\n      \u003CSuspense fallback={\u003CRecommendationsSkeleton />}>\n        \u003CRecommendationsSection recommendationsPromise={recommendationsPromise} />\n      \u003C/Suspense>\n    \u003C/>\n  )\n}\n",[335],{"type":27,"tag":41,"props":336,"children":337},{"__ignoreMap":7},[338],{"type":33,"value":333},{"type":27,"tag":35,"props":340,"children":341},{},[342],{"type":33,"value":343},"这类拆分适合：",{"type":27,"tag":345,"props":346,"children":347},"ul",{},[348,353,358],{"type":27,"tag":270,"props":349,"children":350},{},[351],{"type":33,"value":352},"主信息与补充信息优先级不同",{"type":27,"tag":270,"props":354,"children":355},{},[356],{"type":33,"value":357},"某块内容更慢，但不该拖累整个首屏",{"type":27,"tag":270,"props":359,"children":360},{},[361],{"type":33,"value":362},"页面希望尽快进入“可读状态”",{"type":27,"tag":35,"props":364,"children":365},{},[366],{"type":33,"value":367},"不适合的场景则包括：首屏核心信息本身就依赖完整数据，或者骨架屏比真实内容更复杂，反而增加认知负担。",{"type":27,"tag":63,"props":369,"children":370},{},[],{"type":27,"tag":28,"props":372,"children":374},{"id":373},"_5-常见的瀑布请求是怎么形成的",[375],{"type":33,"value":376},"5. 常见的瀑布请求是怎么形成的",{"type":27,"tag":35,"props":378,"children":379},{},[380],{"type":33,"value":381},"工程里真正难发现的不是显式顺序，而是“结构性瀑布”：",{"type":27,"tag":266,"props":383,"children":384},{},[385,390,395,400],{"type":27,"tag":270,"props":386,"children":387},{},[388],{"type":33,"value":389},"父组件等自己的数据",{"type":27,"tag":270,"props":391,"children":392},{},[393],{"type":33,"value":394},"渲染子组件",{"type":27,"tag":270,"props":396,"children":397},{},[398],{"type":33,"value":399},"子组件再开始请求自己的数据",{"type":27,"tag":270,"props":401,"children":402},{},[403],{"type":33,"value":404},"孙组件继续等待",{"type":27,"tag":35,"props":406,"children":407},{},[408],{"type":33,"value":409},"从代码可读性看似自然，从性能上却会层层串行。",{"type":27,"tag":35,"props":411,"children":412},{},[413],{"type":33,"value":414},"典型信号包括：",{"type":27,"tag":345,"props":416,"children":417},{},[418,423,428],{"type":27,"tag":270,"props":419,"children":420},{},[421],{"type":33,"value":422},"页面层级越深，TTFB 越差",{"type":27,"tag":270,"props":424,"children":425},{},[426],{"type":33,"value":427},"DevTools 中请求呈阶梯式出现",{"type":27,"tag":270,"props":429,"children":430},{},[431],{"type":33,"value":432},"单个接口不慢，但页面整体很慢",{"type":27,"tag":35,"props":434,"children":435},{},[436],{"type":33,"value":437},"解决思路通常有三种：",{"type":27,"tag":345,"props":439,"children":440},{},[441,446,451],{"type":27,"tag":270,"props":442,"children":443},{},[444],{"type":33,"value":445},"把互不依赖的请求提升到更高层，提前发起",{"type":27,"tag":270,"props":447,"children":448},{},[449],{"type":33,"value":450},"用 Suspense 拆边界，而不是等父组件把一切拿全",{"type":27,"tag":270,"props":452,"children":453},{},[454],{"type":33,"value":455},"对稳定数据使用缓存，避免每次都从零开始串行计算",{"type":27,"tag":63,"props":457,"children":458},{},[],{"type":27,"tag":28,"props":460,"children":462},{"id":461},"_6-决策框架页面级数据获取应该怎么设计",[463],{"type":33,"value":464},"6. 决策框架：页面级数据获取应该怎么设计",{"type":27,"tag":35,"props":466,"children":467},{},[468],{"type":33,"value":469},"可以把每个页面的数据分成四层：",{"type":27,"tag":78,"props":471,"children":472},{},[473,494],{"type":27,"tag":82,"props":474,"children":475},{},[476],{"type":27,"tag":86,"props":477,"children":478},{},[479,484,489],{"type":27,"tag":90,"props":480,"children":481},{},[482],{"type":33,"value":483},"层级",{"type":27,"tag":90,"props":485,"children":486},{},[487],{"type":33,"value":488},"典型内容",{"type":27,"tag":90,"props":490,"children":491},{},[492],{"type":33,"value":493},"建议",{"type":27,"tag":106,"props":495,"children":496},{},[497,515,533,551],{"type":27,"tag":86,"props":498,"children":499},{},[500,505,510],{"type":27,"tag":113,"props":501,"children":502},{},[503],{"type":33,"value":504},"全局层",{"type":27,"tag":113,"props":506,"children":507},{},[508],{"type":33,"value":509},"导航、站点配置、当前用户",{"type":27,"tag":113,"props":511,"children":512},{},[513],{"type":33,"value":514},"布局层获取，尽量复用缓存",{"type":27,"tag":86,"props":516,"children":517},{},[518,523,528],{"type":27,"tag":113,"props":519,"children":520},{},[521],{"type":33,"value":522},"首屏层",{"type":27,"tag":113,"props":524,"children":525},{},[526],{"type":33,"value":527},"文章正文、商品主体、关键报表",{"type":27,"tag":113,"props":529,"children":530},{},[531],{"type":33,"value":532},"优先返回，避免被低优先级内容阻塞",{"type":27,"tag":86,"props":534,"children":535},{},[536,541,546],{"type":27,"tag":113,"props":537,"children":538},{},[539],{"type":33,"value":540},"支撑层",{"type":27,"tag":113,"props":542,"children":543},{},[544],{"type":33,"value":545},"推荐内容、评论摘要、相关模块",{"type":27,"tag":113,"props":547,"children":548},{},[549],{"type":33,"value":550},"并行发起，按边界延后展示",{"type":27,"tag":86,"props":552,"children":553},{},[554,559,564],{"type":27,"tag":113,"props":555,"children":556},{},[557],{"type":33,"value":558},"增强层",{"type":27,"tag":113,"props":560,"children":561},{},[562],{"type":33,"value":563},"实验模块、统计补充、个性化推荐",{"type":27,"tag":113,"props":565,"children":566},{},[567],{"type":33,"value":568},"可流式、可懒加载、可降级",{"type":27,"tag":35,"props":570,"children":571},{},[572],{"type":33,"value":573},"很多“性能问题”其实来自层级混乱：把增强层当成首屏层对待，结果整个页面都背上不必要的等待成本。",{"type":27,"tag":63,"props":575,"children":576},{},[],{"type":27,"tag":28,"props":578,"children":580},{"id":579},"_7-失败案例为了减少代码重复最后把页面做成串行",[581],{"type":33,"value":582},"7. 失败案例：为了减少代码重复，最后把页面做成串行",{"type":27,"tag":35,"props":584,"children":585},{},[586],{"type":33,"value":587},"常见反模式是抽一个“万能加载器”：",{"type":27,"tag":201,"props":589,"children":594},{"className":590,"code":592,"language":593,"meta":7},[591],"language-ts","async function loadPageData(slug: string) {\n  const article = await getArticle(slug)\n  const author = await getAuthor(article.authorId)\n  const related = await getRelatedArticles(article.id)\n  const comments = await getComments(article.id)\n\n  return { article, author, related, comments }\n}\n","ts",[595],{"type":27,"tag":41,"props":596,"children":597},{"__ignoreMap":7},[598],{"type":33,"value":592},{"type":27,"tag":35,"props":600,"children":601},{},[602],{"type":33,"value":603},"看起来集中管理、调用方便，但代价是：",{"type":27,"tag":345,"props":605,"children":606},{},[607,612,617],{"type":27,"tag":270,"props":608,"children":609},{},[610],{"type":33,"value":611},"所有请求都被强行收进一个顺序函数",{"type":27,"tag":270,"props":613,"children":614},{},[615],{"type":33,"value":616},"无法按优先级拆分 Suspense",{"type":27,"tag":270,"props":618,"children":619},{},[620],{"type":33,"value":621},"某个低价值接口变慢，会拖死整页",{"type":27,"tag":35,"props":623,"children":624},{},[625],{"type":33,"value":626},"更合理的方式是：把真正有依赖的逻辑留在一起，把可并行、可独立降级的部分拆出来。",{"type":27,"tag":63,"props":628,"children":629},{},[],{"type":27,"tag":28,"props":631,"children":633},{"id":632},"_8-checklist上线前至少检查这-7-件事",[634],{"type":33,"value":635},"8. Checklist：上线前至少检查这 7 件事",{"type":27,"tag":345,"props":637,"children":638},{},[639,651,656,661,666,671,676],{"type":27,"tag":270,"props":640,"children":641},{},[642,644,649],{"type":33,"value":643},"页面里的多个 ",{"type":27,"tag":41,"props":645,"children":647},{"className":646},[],[648],{"type":33,"value":54},{"type":33,"value":650}," 是否真的存在依赖关系",{"type":27,"tag":270,"props":652,"children":653},{},[654],{"type":33,"value":655},"是否有可提前发起但被组件层级拖晚的请求",{"type":27,"tag":270,"props":657,"children":658},{},[659],{"type":33,"value":660},"首屏核心内容是否与低优先级模块共用同一个等待点",{"type":27,"tag":270,"props":662,"children":663},{},[664],{"type":33,"value":665},"是否使用 Suspense 隔离慢模块",{"type":27,"tag":270,"props":667,"children":668},{},[669],{"type":33,"value":670},"是否把权限校验与业务查询关系表达清楚",{"type":27,"tag":270,"props":672,"children":673},{},[674],{"type":33,"value":675},"是否对稳定数据使用了合理缓存",{"type":27,"tag":270,"props":677,"children":678},{},[679],{"type":33,"value":680},"是否在真实网络环境下观察过请求是并行还是阶梯式触发",{"type":27,"tag":63,"props":682,"children":683},{},[],{"type":27,"tag":28,"props":685,"children":687},{"id":686},"_9-结论不是并行越多越好而是等待必须有理由",[688],{"type":33,"value":689},"9. 结论：不是“并行越多越好”，而是“等待必须有理由”",{"type":27,"tag":35,"props":691,"children":692},{},[693],{"type":33,"value":694},"Next.js 的数据获取设计，重点从来不是把所有请求写成某个固定模式，而是让等待与依赖关系对齐。互不依赖的数据，要尽快发起并避免无意义阻塞；必须顺序的数据，要把业务理由写清楚；优先级不同的模块，则交给 Suspense 去拆开体验边界。",{"type":27,"tag":35,"props":696,"children":697},{},[698],{"type":33,"value":699},"如果你正在继续完善 App Router 的工程实践，可以再读这几篇：",{"type":27,"tag":345,"props":701,"children":702},{},[703,713,722],{"type":27,"tag":270,"props":704,"children":705},{},[706],{"type":27,"tag":707,"props":708,"children":710},"a",{"href":709},"/topics/next/server-actions-complete-guide",[711],{"type":33,"value":712},"Server Actions 完整指南",{"type":27,"tag":270,"props":714,"children":715},{},[716],{"type":27,"tag":707,"props":717,"children":719},{"href":718},"/topics/next/cache-strategy-deep-dive",[720],{"type":33,"value":721},"缓存策略深度解析",{"type":27,"tag":270,"props":723,"children":724},{},[725],{"type":27,"tag":707,"props":726,"children":728},{"href":727},"/topics/next/react-server-components-deep-dive",[729],{"type":33,"value":730},"React Server Components 深度解析",{"title":7,"searchDepth":732,"depth":732,"links":733},3,[734,736,737,738,739,740,741,742,743,744],{"id":30,"depth":735,"text":8},2,{"id":68,"depth":735,"text":71},{"id":191,"depth":735,"text":194},{"id":251,"depth":735,"text":254},{"id":314,"depth":735,"text":317},{"id":373,"depth":735,"text":376},{"id":461,"depth":735,"text":464},{"id":579,"depth":735,"text":582},{"id":632,"depth":735,"text":635},{"id":686,"depth":735,"text":689},"markdown","content:topics:next:parallel-sequential-data-fetching-guide.md","content","topics/next/parallel-sequential-data-fetching-guide.md","topics/next/parallel-sequential-data-fetching-guide","md",[752,1938,2748],{"_path":718,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":721,"description":753,"date":754,"topic":5,"author":11,"tags":755,"image":760,"featured":761,"readingTime":762,"body":763,"_type":745,"_id":1935,"_source":747,"_file":1936,"_stem":1937,"_extension":750},"从 HTTP/CDN 到 Next.js App Router 的缓存语义，系统拆解缓存的分层模型、失效策略与常见踩坑，给出可直接落地的工程化方案与检查清单。","2026-01-20",[756,757,13,14,758,759],"缓存","CDN","revalidateTag","Cache-Control","/images/topics/next/cache-strategy.jpg",true,22,{"type":24,"children":764,"toc":1901},[765,769,782,787,805,810,828,833,836,842,847,890,895,913,920,933,938,941,947,952,1016,1022,1027,1038,1043,1061,1067,1072,1091,1101,1104,1110,1115,1128,1133,1139,1144,1209,1222,1228,1233,1260,1263,1269,1274,1297,1303,1308,1326,1331,1337,1362,1367,1380,1383,1389,1394,1412,1418,1423,1453,1458,1483,1488,1494,1505,1523,1526,1532,1538,1556,1562,1580,1585,1598,1601,1607,1612,1640,1645,1674,1677,1683,1689,1727,1733,1775,1781,1799,1802,1808,1870,1873,1878,1883],{"type":27,"tag":28,"props":766,"children":767},{"id":721},[768],{"type":33,"value":721},{"type":27,"tag":35,"props":770,"children":771},{},[772,774,780],{"type":33,"value":773},"缓存不是“开关”，而是一套",{"type":27,"tag":775,"props":776,"children":777},"strong",{},[778],{"type":33,"value":779},"分层一致性工程",{"type":33,"value":781},"。",{"type":27,"tag":35,"props":783,"children":784},{},[785],{"type":33,"value":786},"做得好，缓存能同时提升：",{"type":27,"tag":345,"props":788,"children":789},{},[790,795,800],{"type":27,"tag":270,"props":791,"children":792},{},[793],{"type":33,"value":794},"TTFB / LCP（更快）",{"type":27,"tag":270,"props":796,"children":797},{},[798],{"type":33,"value":799},"稳定性（抗突发流量、抗抖动）",{"type":27,"tag":270,"props":801,"children":802},{},[803],{"type":33,"value":804},"成本（更少的源站请求）",{"type":27,"tag":35,"props":806,"children":807},{},[808],{"type":33,"value":809},"做得不好，缓存会制造更可怕的问题：",{"type":27,"tag":345,"props":811,"children":812},{},[813,818,823],{"type":27,"tag":270,"props":814,"children":815},{},[816],{"type":33,"value":817},"用户看到过期数据，且你无法复现",{"type":27,"tag":270,"props":819,"children":820},{},[821],{"type":33,"value":822},"A 用户的内容被 B 用户读到（严重安全事故）",{"type":27,"tag":270,"props":824,"children":825},{},[826],{"type":33,"value":827},"缓存命中率很低，反而更慢、更贵",{"type":27,"tag":35,"props":829,"children":830},{},[831],{"type":33,"value":832},"这篇文章的目标是：让你用一套统一的心智模型，设计并落地“可控、可观测、可回滚”的缓存系统。并以 Next.js App Router 为例，把框架缓存语义纳入整套设计。",{"type":27,"tag":63,"props":834,"children":835},{},[],{"type":27,"tag":28,"props":837,"children":839},{"id":838},"_1-先建立缓存的分层模型",[840],{"type":33,"value":841},"1. 先建立缓存的“分层模型”",{"type":27,"tag":35,"props":843,"children":844},{},[845],{"type":33,"value":846},"真实系统的缓存几乎总是分层的：",{"type":27,"tag":266,"props":848,"children":849},{},[850,860,870,880],{"type":27,"tag":270,"props":851,"children":852},{},[853,858],{"type":27,"tag":775,"props":854,"children":855},{},[856],{"type":33,"value":857},"浏览器缓存",{"type":33,"value":859},"（Browser Cache）",{"type":27,"tag":270,"props":861,"children":862},{},[863,868],{"type":27,"tag":775,"props":864,"children":865},{},[866],{"type":33,"value":867},"CDN/边缘缓存",{"type":33,"value":869},"（Edge Cache）",{"type":27,"tag":270,"props":871,"children":872},{},[873,878],{"type":27,"tag":775,"props":874,"children":875},{},[876],{"type":33,"value":877},"应用侧缓存",{"type":33,"value":879},"（App Cache：SSR/RSC payload、fetch cache）",{"type":27,"tag":270,"props":881,"children":882},{},[883,888],{"type":27,"tag":775,"props":884,"children":885},{},[886],{"type":33,"value":887},"数据侧缓存",{"type":33,"value":889},"（Redis/DB buffer）",{"type":27,"tag":35,"props":891,"children":892},{},[893],{"type":33,"value":894},"你需要明确：",{"type":27,"tag":345,"props":896,"children":897},{},[898,903,908],{"type":27,"tag":270,"props":899,"children":900},{},[901],{"type":33,"value":902},"每一层缓存什么？（HTML / JSON / 静态资源 / RSC payload）",{"type":27,"tag":270,"props":904,"children":905},{},[906],{"type":33,"value":907},"每一层的 TTL 多久？",{"type":27,"tag":270,"props":909,"children":910},{},[911],{"type":33,"value":912},"写操作发生后，哪几层需要失效？",{"type":27,"tag":914,"props":915,"children":917},"h3",{"id":916},"_11-缓存的两类问题性能与一致性",[918],{"type":33,"value":919},"1.1 缓存的两类问题：性能与一致性",{"type":27,"tag":345,"props":921,"children":922},{},[923,928],{"type":27,"tag":270,"props":924,"children":925},{},[926],{"type":33,"value":927},"性能问题：命中率、压缩、复用、减少源站",{"type":27,"tag":270,"props":929,"children":930},{},[931],{"type":33,"value":932},"一致性问题：失效、隔离、权限、版本",{"type":27,"tag":35,"props":934,"children":935},{},[936],{"type":33,"value":937},"很多团队“缓存做不好”，本质是只解决了性能，忽略了一致性。",{"type":27,"tag":63,"props":939,"children":940},{},[],{"type":27,"tag":28,"props":942,"children":944},{"id":943},"_2-http-缓存基础cache-control-的正确用法",[945],{"type":33,"value":946},"2. HTTP 缓存基础：Cache-Control 的正确用法",{"type":27,"tag":35,"props":948,"children":949},{},[950],{"type":33,"value":951},"HTTP 缓存是地基。你至少要掌握这些指令：",{"type":27,"tag":345,"props":953,"children":954},{},[955,972,983,994,1005],{"type":27,"tag":270,"props":956,"children":957},{},[958,964,966],{"type":27,"tag":41,"props":959,"children":961},{"className":960},[],[962],{"type":33,"value":963},"public",{"type":33,"value":965}," / ",{"type":27,"tag":41,"props":967,"children":969},{"className":968},[],[970],{"type":33,"value":971},"private",{"type":27,"tag":270,"props":973,"children":974},{},[975,981],{"type":27,"tag":41,"props":976,"children":978},{"className":977},[],[979],{"type":33,"value":980},"max-age",{"type":33,"value":982},"（强缓存 TTL）",{"type":27,"tag":270,"props":984,"children":985},{},[986,992],{"type":27,"tag":41,"props":987,"children":989},{"className":988},[],[990],{"type":33,"value":991},"s-maxage",{"type":33,"value":993},"（CDN 侧 TTL）",{"type":27,"tag":270,"props":995,"children":996},{},[997,1003],{"type":27,"tag":41,"props":998,"children":1000},{"className":999},[],[1001],{"type":33,"value":1002},"stale-while-revalidate",{"type":33,"value":1004},"（过期可先用旧的，再后台更新）",{"type":27,"tag":270,"props":1006,"children":1007},{},[1008,1014],{"type":27,"tag":41,"props":1009,"children":1011},{"className":1010},[],[1012],{"type":33,"value":1013},"no-store",{"type":33,"value":1015},"（不要存储）",{"type":27,"tag":914,"props":1017,"children":1019},{"id":1018},"_21-一个常用的-cdn-缓存头模板",[1020],{"type":33,"value":1021},"2.1 一个常用的 CDN 缓存头模板",{"type":27,"tag":35,"props":1023,"children":1024},{},[1025],{"type":33,"value":1026},"对“公共页面（无用户态）”：",{"type":27,"tag":201,"props":1028,"children":1033},{"className":1029,"code":1031,"language":1032,"meta":7},[1030],"language-http","Cache-Control: public, max-age=0, s-maxage=600, stale-while-revalidate=86400\n","http",[1034],{"type":27,"tag":41,"props":1035,"children":1036},{"__ignoreMap":7},[1037],{"type":33,"value":1031},{"type":27,"tag":35,"props":1039,"children":1040},{},[1041],{"type":33,"value":1042},"含义：",{"type":27,"tag":345,"props":1044,"children":1045},{},[1046,1051,1056],{"type":27,"tag":270,"props":1047,"children":1048},{},[1049],{"type":33,"value":1050},"浏览器不强缓存（max-age=0）",{"type":27,"tag":270,"props":1052,"children":1053},{},[1054],{"type":33,"value":1055},"CDN 缓存 10 分钟",{"type":27,"tag":270,"props":1057,"children":1058},{},[1059],{"type":33,"value":1060},"CDN 过期后仍可先用旧内容 1 天，同时异步更新",{"type":27,"tag":914,"props":1062,"children":1064},{"id":1063},"_22-用户态页面默认-private-或-no-store",[1065],{"type":33,"value":1066},"2.2 用户态页面：默认 private 或 no-store",{"type":27,"tag":35,"props":1068,"children":1069},{},[1070],{"type":33,"value":1071},"一旦响应与用户身份有关：",{"type":27,"tag":345,"props":1073,"children":1074},{},[1075,1086],{"type":27,"tag":270,"props":1076,"children":1077},{},[1078,1080],{"type":33,"value":1079},"默认：",{"type":27,"tag":41,"props":1081,"children":1083},{"className":1082},[],[1084],{"type":33,"value":1085},"Cache-Control: private, no-store",{"type":27,"tag":270,"props":1087,"children":1088},{},[1089],{"type":33,"value":1090},"必须缓存时：缓存 key 必须包含用户维度（例如 userId/session）且只在应用侧缓存",{"type":27,"tag":35,"props":1092,"children":1093},{},[1094,1096],{"type":33,"value":1095},"结论：",{"type":27,"tag":775,"props":1097,"children":1098},{},[1099],{"type":33,"value":1100},"宁可慢一点，也不要把用户态响应交给 CDN 缓存。",{"type":27,"tag":63,"props":1102,"children":1103},{},[],{"type":27,"tag":28,"props":1105,"children":1107},{"id":1106},"_3-cdn-缓存命中率与-key-设计",[1108],{"type":33,"value":1109},"3. CDN 缓存：命中率与 Key 设计",{"type":27,"tag":35,"props":1111,"children":1112},{},[1113],{"type":33,"value":1114},"CDN 缓存的核心是：",{"type":27,"tag":345,"props":1116,"children":1117},{},[1118,1123],{"type":27,"tag":270,"props":1119,"children":1120},{},[1121],{"type":33,"value":1122},"你希望命中（hit），就要让相同内容的请求尽可能“看起来一样”",{"type":27,"tag":270,"props":1124,"children":1125},{},[1126],{"type":33,"value":1127},"你希望隔离（safe），就要让不同内容的请求“必须不一样”",{"type":27,"tag":35,"props":1129,"children":1130},{},[1131],{"type":33,"value":1132},"这两个目标天然冲突。",{"type":27,"tag":914,"props":1134,"children":1136},{"id":1135},"_31-cache-key-里哪些维度必须考虑",[1137],{"type":33,"value":1138},"3.1 Cache Key 里哪些维度必须考虑？",{"type":27,"tag":35,"props":1140,"children":1141},{},[1142],{"type":33,"value":1143},"最常见维度：",{"type":27,"tag":345,"props":1145,"children":1146},{},[1147,1156,1165,1176,1187,1198],{"type":27,"tag":270,"props":1148,"children":1149},{},[1150],{"type":27,"tag":41,"props":1151,"children":1153},{"className":1152},[],[1154],{"type":33,"value":1155},"host",{"type":27,"tag":270,"props":1157,"children":1158},{},[1159],{"type":27,"tag":41,"props":1160,"children":1162},{"className":1161},[],[1163],{"type":33,"value":1164},"path",{"type":27,"tag":270,"props":1166,"children":1167},{},[1168,1174],{"type":27,"tag":41,"props":1169,"children":1171},{"className":1170},[],[1172],{"type":33,"value":1173},"query",{"type":33,"value":1175},"（是否纳入 key？）",{"type":27,"tag":270,"props":1177,"children":1178},{},[1179,1185],{"type":27,"tag":41,"props":1180,"children":1182},{"className":1181},[],[1183],{"type":33,"value":1184},"accept-encoding",{"type":33,"value":1186},"（gzip/br）",{"type":27,"tag":270,"props":1188,"children":1189},{},[1190,1196],{"type":27,"tag":41,"props":1191,"children":1193},{"className":1192},[],[1194],{"type":33,"value":1195},"accept-language",{"type":33,"value":1197},"（多语言站点）",{"type":27,"tag":270,"props":1199,"children":1200},{},[1201,1207],{"type":27,"tag":41,"props":1202,"children":1204},{"className":1203},[],[1205],{"type":33,"value":1206},"device",{"type":33,"value":1208},"（移动/桌面，如果你做了 UA vary）",{"type":27,"tag":35,"props":1210,"children":1211},{},[1212,1214,1220],{"type":33,"value":1213},"反例：把“跟内容无关的 query”放进 key（例如 ",{"type":27,"tag":41,"props":1215,"children":1217},{"className":1216},[],[1218],{"type":33,"value":1219},"utm_*",{"type":33,"value":1221},"），会把命中率直接打碎。",{"type":27,"tag":914,"props":1223,"children":1225},{"id":1224},"_32-解决-utm-污染规范化-url",[1226],{"type":33,"value":1227},"3.2 解决 UTM 污染：规范化 URL",{"type":27,"tag":35,"props":1229,"children":1230},{},[1231],{"type":33,"value":1232},"建议：",{"type":27,"tag":345,"props":1234,"children":1235},{},[1236,1248],{"type":27,"tag":270,"props":1237,"children":1238},{},[1239,1241,1246],{"type":33,"value":1240},"进入应用时把 ",{"type":27,"tag":41,"props":1242,"children":1244},{"className":1243},[],[1245],{"type":33,"value":1219},{"type":33,"value":1247}," 归一化并 301 到干净 URL",{"type":27,"tag":270,"props":1249,"children":1250},{},[1251,1253,1258],{"type":33,"value":1252},"或在 CDN 层将 ",{"type":27,"tag":41,"props":1254,"children":1256},{"className":1255},[],[1257],{"type":33,"value":1219},{"type":33,"value":1259}," 从 cache key 里剔除",{"type":27,"tag":63,"props":1261,"children":1262},{},[],{"type":27,"tag":28,"props":1264,"children":1266},{"id":1265},"_4-应用侧缓存nextjs-app-router-的缓存语义",[1267],{"type":33,"value":1268},"4. 应用侧缓存：Next.js App Router 的缓存语义",{"type":27,"tag":35,"props":1270,"children":1271},{},[1272],{"type":33,"value":1273},"App Router 的“缓存”不是一个地方，而是一套语义：",{"type":27,"tag":345,"props":1275,"children":1276},{},[1277,1282,1287,1292],{"type":27,"tag":270,"props":1278,"children":1279},{},[1280],{"type":33,"value":1281},"fetch 结果缓存",{"type":27,"tag":270,"props":1283,"children":1284},{},[1285],{"type":33,"value":1286},"RSC payload 缓存",{"type":27,"tag":270,"props":1288,"children":1289},{},[1290],{"type":33,"value":1291},"route segment 缓存",{"type":27,"tag":270,"props":1293,"children":1294},{},[1295],{"type":33,"value":1296},"revalidate 机制（path/tag）",{"type":27,"tag":914,"props":1298,"children":1300},{"id":1299},"_41-你必须区分静态动态按需再验证",[1301],{"type":33,"value":1302},"4.1 你必须区分：静态、动态、按需再验证",{"type":27,"tag":35,"props":1304,"children":1305},{},[1306],{"type":33,"value":1307},"在 App Router 体系里，一个页面/段可以是：",{"type":27,"tag":345,"props":1309,"children":1310},{},[1311,1316,1321],{"type":27,"tag":270,"props":1312,"children":1313},{},[1314],{"type":33,"value":1315},"静态（长 TTL）",{"type":27,"tag":270,"props":1317,"children":1318},{},[1319],{"type":33,"value":1320},"动态（每次都算）",{"type":27,"tag":270,"props":1322,"children":1323},{},[1324],{"type":33,"value":1325},"ISR/按需再验证（写操作后失效）",{"type":27,"tag":35,"props":1327,"children":1328},{},[1329],{"type":33,"value":1330},"不要把“页面慢”简单归因给 SSR；很多时候是缓存策略没设计好。",{"type":27,"tag":914,"props":1332,"children":1334},{"id":1333},"_42-两个最重要的失效-apirevalidatepath-revalidatetag",[1335],{"type":33,"value":1336},"4.2 两个最重要的失效 API：revalidatePath / revalidateTag",{"type":27,"tag":345,"props":1338,"children":1339},{},[1340,1351],{"type":27,"tag":270,"props":1341,"children":1342},{},[1343,1349],{"type":27,"tag":41,"props":1344,"children":1346},{"className":1345},[],[1347],{"type":33,"value":1348},"revalidatePath('/xxx')",{"type":33,"value":1350},"：按路由失效（粗粒度）",{"type":27,"tag":270,"props":1352,"children":1353},{},[1354,1360],{"type":27,"tag":41,"props":1355,"children":1357},{"className":1356},[],[1358],{"type":33,"value":1359},"revalidateTag('tag')",{"type":33,"value":1361},"：按数据域失效（细粒度）",{"type":27,"tag":35,"props":1363,"children":1364},{},[1365],{"type":33,"value":1366},"经验法则：",{"type":27,"tag":345,"props":1368,"children":1369},{},[1370,1375],{"type":27,"tag":270,"props":1371,"children":1372},{},[1373],{"type":33,"value":1374},"数据只影响单页：用 path",{"type":27,"tag":270,"props":1376,"children":1377},{},[1378],{"type":33,"value":1379},"数据影响多页（列表、详情、侧栏统计）：用 tag",{"type":27,"tag":63,"props":1381,"children":1382},{},[],{"type":27,"tag":28,"props":1384,"children":1386},{"id":1385},"_5-写操作后的失效策略从拍脑袋到可证明",[1387],{"type":33,"value":1388},"5. 写操作后的失效策略：从“拍脑袋”到“可证明”",{"type":27,"tag":35,"props":1390,"children":1391},{},[1392],{"type":33,"value":1393},"写操作发生后，你要回答：",{"type":27,"tag":345,"props":1395,"children":1396},{},[1397,1402,1407],{"type":27,"tag":270,"props":1398,"children":1399},{},[1400],{"type":33,"value":1401},"哪些页面会受影响？",{"type":27,"tag":270,"props":1403,"children":1404},{},[1405],{"type":33,"value":1406},"哪些数据域会受影响？",{"type":27,"tag":270,"props":1408,"children":1409},{},[1410],{"type":33,"value":1411},"这些受影响对象是否有统一 tag？",{"type":27,"tag":914,"props":1413,"children":1415},{"id":1414},"_51-建议采用域驱动-tag",[1416],{"type":33,"value":1417},"5.1 建议采用“域驱动 tag”",{"type":27,"tag":35,"props":1419,"children":1420},{},[1421],{"type":33,"value":1422},"例子：电商商品",{"type":27,"tag":345,"props":1424,"children":1425},{},[1426,1435,1444],{"type":27,"tag":270,"props":1427,"children":1428},{},[1429],{"type":27,"tag":41,"props":1430,"children":1432},{"className":1431},[],[1433],{"type":33,"value":1434},"product:{id}",{"type":27,"tag":270,"props":1436,"children":1437},{},[1438],{"type":27,"tag":41,"props":1439,"children":1441},{"className":1440},[],[1442],{"type":33,"value":1443},"product:list",{"type":27,"tag":270,"props":1445,"children":1446},{},[1447],{"type":27,"tag":41,"props":1448,"children":1450},{"className":1449},[],[1451],{"type":33,"value":1452},"inventory:{id}",{"type":27,"tag":35,"props":1454,"children":1455},{},[1456],{"type":33,"value":1457},"当你更新库存时：",{"type":27,"tag":345,"props":1459,"children":1460},{},[1461,1471],{"type":27,"tag":270,"props":1462,"children":1463},{},[1464,1466],{"type":33,"value":1465},"失效 ",{"type":27,"tag":41,"props":1467,"children":1469},{"className":1468},[],[1470],{"type":33,"value":1452},{"type":27,"tag":270,"props":1472,"children":1473},{},[1474,1476,1481],{"type":33,"value":1475},"可能也失效 ",{"type":27,"tag":41,"props":1477,"children":1479},{"className":1478},[],[1480],{"type":33,"value":1434},{"type":33,"value":1482},"（如果详情页展示库存）",{"type":27,"tag":35,"props":1484,"children":1485},{},[1486],{"type":33,"value":1487},"这样你可以把失效做成一套规则，而不是散落在业务代码里。",{"type":27,"tag":914,"props":1489,"children":1491},{"id":1490},"_52-不要用全站失效当默认",[1492],{"type":33,"value":1493},"5.2 不要用“全站失效”当默认",{"type":27,"tag":35,"props":1495,"children":1496},{},[1497,1503],{"type":27,"tag":41,"props":1498,"children":1500},{"className":1499},[],[1501],{"type":33,"value":1502},"revalidatePath('/')",{"type":33,"value":1504},"、清 CDN 全站缓存，短期看省事，长期一定出问题：",{"type":27,"tag":345,"props":1506,"children":1507},{},[1508,1513,1518],{"type":27,"tag":270,"props":1509,"children":1510},{},[1511],{"type":33,"value":1512},"命中率暴跌",{"type":27,"tag":270,"props":1514,"children":1515},{},[1516],{"type":33,"value":1517},"源站被打穿",{"type":27,"tag":270,"props":1519,"children":1520},{},[1521],{"type":33,"value":1522},"回归定位困难",{"type":27,"tag":63,"props":1524,"children":1525},{},[],{"type":27,"tag":28,"props":1527,"children":1529},{"id":1528},"_6-缓存与权限最危险的组合",[1530],{"type":33,"value":1531},"6. 缓存与权限：最危险的组合",{"type":27,"tag":914,"props":1533,"children":1535},{"id":1534},"_61-三条硬规则",[1536],{"type":33,"value":1537},"6.1 三条硬规则",{"type":27,"tag":345,"props":1539,"children":1540},{},[1541,1546,1551],{"type":27,"tag":270,"props":1542,"children":1543},{},[1544],{"type":33,"value":1545},"用户态响应不要进 CDN",{"type":27,"tag":270,"props":1547,"children":1548},{},[1549],{"type":33,"value":1550},"缓存 key 必须包含权限维度（userId/role）",{"type":27,"tag":270,"props":1552,"children":1553},{},[1554],{"type":33,"value":1555},"SSR 页面要明确区分“公共数据”与“私有数据”",{"type":27,"tag":914,"props":1557,"children":1559},{"id":1558},"_62-常见事故模式",[1560],{"type":33,"value":1561},"6.2 常见事故模式",{"type":27,"tag":345,"props":1563,"children":1564},{},[1565,1570,1575],{"type":27,"tag":270,"props":1566,"children":1567},{},[1568],{"type":33,"value":1569},"详情页同时展示公共内容 + 用户私有信息（例如是否收藏）",{"type":27,"tag":270,"props":1571,"children":1572},{},[1573],{"type":33,"value":1574},"你把整页缓存了",{"type":27,"tag":270,"props":1576,"children":1577},{},[1578],{"type":33,"value":1579},"结果：用户私有信息被缓存并泄漏",{"type":27,"tag":35,"props":1581,"children":1582},{},[1583],{"type":33,"value":1584},"正确做法：",{"type":27,"tag":345,"props":1586,"children":1587},{},[1588,1593],{"type":27,"tag":270,"props":1589,"children":1590},{},[1591],{"type":33,"value":1592},"公共内容可缓存",{"type":27,"tag":270,"props":1594,"children":1595},{},[1596],{"type":33,"value":1597},"私有信息走客户端请求或单独的私有 API（不缓存）",{"type":27,"tag":63,"props":1599,"children":1600},{},[],{"type":27,"tag":28,"props":1602,"children":1604},{"id":1603},"_7-可观测性让缓存变成可量化系统",[1605],{"type":33,"value":1606},"7. 可观测性：让缓存变成“可量化系统”",{"type":27,"tag":35,"props":1608,"children":1609},{},[1610],{"type":33,"value":1611},"你至少需要这些指标：",{"type":27,"tag":345,"props":1613,"children":1614},{},[1615,1620,1625,1630,1635],{"type":27,"tag":270,"props":1616,"children":1617},{},[1618],{"type":33,"value":1619},"CDN 命中率（hit/miss）",{"type":27,"tag":270,"props":1621,"children":1622},{},[1623],{"type":33,"value":1624},"源站 QPS",{"type":27,"tag":270,"props":1626,"children":1627},{},[1628],{"type":33,"value":1629},"TTFB 分布（p50/p95）",{"type":27,"tag":270,"props":1631,"children":1632},{},[1633],{"type":33,"value":1634},"revalidate 调用量与耗时",{"type":27,"tag":270,"props":1636,"children":1637},{},[1638],{"type":33,"value":1639},"失效失败率",{"type":27,"tag":35,"props":1641,"children":1642},{},[1643],{"type":33,"value":1644},"日志建议：",{"type":27,"tag":345,"props":1646,"children":1647},{},[1648,1661],{"type":27,"tag":270,"props":1649,"children":1650},{},[1651,1653,1659],{"type":33,"value":1652},"给每个请求注入 ",{"type":27,"tag":41,"props":1654,"children":1656},{"className":1655},[],[1657],{"type":33,"value":1658},"cacheStatus",{"type":33,"value":1660},"（HIT/MISS/BYPASS）",{"type":27,"tag":270,"props":1662,"children":1663},{},[1664,1666,1672],{"type":33,"value":1665},"记录 ",{"type":27,"tag":41,"props":1667,"children":1669},{"className":1668},[],[1670],{"type":33,"value":1671},"cacheKey",{"type":33,"value":1673}," 的关键维度（注意脱敏）",{"type":27,"tag":63,"props":1675,"children":1676},{},[],{"type":27,"tag":28,"props":1678,"children":1680},{"id":1679},"_8-一份可直接执行的缓存策略模板",[1681],{"type":33,"value":1682},"8. 一份可直接执行的缓存策略模板",{"type":27,"tag":914,"props":1684,"children":1686},{"id":1685},"_81-公共内容页文章落地页",[1687],{"type":33,"value":1688},"8.1 公共内容页（文章、落地页）",{"type":27,"tag":345,"props":1690,"children":1691},{},[1692,1703,1716],{"type":27,"tag":270,"props":1693,"children":1694},{},[1695,1697],{"type":33,"value":1696},"CDN：",{"type":27,"tag":41,"props":1698,"children":1700},{"className":1699},[],[1701],{"type":33,"value":1702},"s-maxage=600, stale-while-revalidate=86400",{"type":27,"tag":270,"props":1704,"children":1705},{},[1706,1708,1714],{"type":33,"value":1707},"App：允许 fetch cache，tag 以 ",{"type":27,"tag":41,"props":1709,"children":1711},{"className":1710},[],[1712],{"type":33,"value":1713},"content:*",{"type":33,"value":1715}," 组织",{"type":27,"tag":270,"props":1717,"children":1718},{},[1719,1721],{"type":33,"value":1720},"写操作：发布文章时 ",{"type":27,"tag":41,"props":1722,"children":1724},{"className":1723},[],[1725],{"type":33,"value":1726},"revalidateTag('content:article')",{"type":27,"tag":914,"props":1728,"children":1730},{"id":1729},"_82-列表-详情强一致性要求不高",[1731],{"type":33,"value":1732},"8.2 列表 + 详情（强一致性要求不高）",{"type":27,"tag":345,"props":1734,"children":1735},{},[1736,1747,1758],{"type":27,"tag":270,"props":1737,"children":1738},{},[1739,1741],{"type":33,"value":1740},"详情：tag ",{"type":27,"tag":41,"props":1742,"children":1744},{"className":1743},[],[1745],{"type":33,"value":1746},"entity:{id}",{"type":27,"tag":270,"props":1748,"children":1749},{},[1750,1752],{"type":33,"value":1751},"列表：tag ",{"type":27,"tag":41,"props":1753,"children":1755},{"className":1754},[],[1756],{"type":33,"value":1757},"entity:list",{"type":27,"tag":270,"props":1759,"children":1760},{},[1761,1763,1768,1770],{"type":33,"value":1762},"更新：失效 ",{"type":27,"tag":41,"props":1764,"children":1766},{"className":1765},[],[1767],{"type":33,"value":1746},{"type":33,"value":1769}," + ",{"type":27,"tag":41,"props":1771,"children":1773},{"className":1772},[],[1774],{"type":33,"value":1757},{"type":27,"tag":914,"props":1776,"children":1778},{"id":1777},"_83-强一致性库存余额",[1779],{"type":33,"value":1780},"8.3 强一致性（库存、余额）",{"type":27,"tag":345,"props":1782,"children":1783},{},[1784,1789,1794],{"type":27,"tag":270,"props":1785,"children":1786},{},[1787],{"type":33,"value":1788},"默认不缓存",{"type":27,"tag":270,"props":1790,"children":1791},{},[1792],{"type":33,"value":1793},"或只做极短 TTL（1~3s）",{"type":27,"tag":270,"props":1795,"children":1796},{},[1797],{"type":33,"value":1798},"必须有幂等与容错",{"type":27,"tag":63,"props":1800,"children":1801},{},[],{"type":27,"tag":28,"props":1803,"children":1805},{"id":1804},"_9-检查清单上线前必过",[1806],{"type":33,"value":1807},"9. 检查清单（上线前必过）",{"type":27,"tag":345,"props":1809,"children":1812},{"className":1810},[1811],"contains-task-list",[1813,1825,1834,1843,1852,1861],{"type":27,"tag":270,"props":1814,"children":1817},{"className":1815},[1816],"task-list-item",[1818,1823],{"type":27,"tag":1819,"props":1820,"children":1822},"input",{"disabled":761,"type":1821},"checkbox",[],{"type":33,"value":1824}," 哪些路由是 public/private？是否明确",{"type":27,"tag":270,"props":1826,"children":1828},{"className":1827},[1816],[1829,1832],{"type":27,"tag":1819,"props":1830,"children":1831},{"disabled":761,"type":1821},[],{"type":33,"value":1833}," CDN cache key 是否会被无关 query 污染",{"type":27,"tag":270,"props":1835,"children":1837},{"className":1836},[1816],[1838,1841],{"type":27,"tag":1819,"props":1839,"children":1840},{"disabled":761,"type":1821},[],{"type":33,"value":1842}," 用户态响应是否有 no-store",{"type":27,"tag":270,"props":1844,"children":1846},{"className":1845},[1816],[1847,1850],{"type":27,"tag":1819,"props":1848,"children":1849},{"disabled":761,"type":1821},[],{"type":33,"value":1851}," 写操作是否有明确的 tag/path 失效策略",{"type":27,"tag":270,"props":1853,"children":1855},{"className":1854},[1816],[1856,1859],{"type":27,"tag":1819,"props":1857,"children":1858},{"disabled":761,"type":1821},[],{"type":33,"value":1860}," 是否有命中率与回源监控",{"type":27,"tag":270,"props":1862,"children":1864},{"className":1863},[1816],[1865,1868],{"type":27,"tag":1819,"props":1866,"children":1867},{"disabled":761,"type":1821},[],{"type":33,"value":1869}," 回滚策略是什么（关缓存、降级）",{"type":27,"tag":63,"props":1871,"children":1872},{},[],{"type":27,"tag":28,"props":1874,"children":1876},{"id":1875},"总结",[1877],{"type":33,"value":1875},{"type":27,"tag":35,"props":1879,"children":1880},{},[1881],{"type":33,"value":1882},"缓存策略的本质是：",{"type":27,"tag":345,"props":1884,"children":1885},{},[1886,1891,1896],{"type":27,"tag":270,"props":1887,"children":1888},{},[1889],{"type":33,"value":1890},"把“快”变成可控的工程系统",{"type":27,"tag":270,"props":1892,"children":1893},{},[1894],{"type":33,"value":1895},"把“一致性”变成可证明的规则",{"type":27,"tag":270,"props":1897,"children":1898},{},[1899],{"type":33,"value":1900},"把“失效”变成可观测、可回滚的流程",{"title":7,"searchDepth":732,"depth":732,"links":1902},[1903,1904,1907,1911,1915,1919,1923,1927,1928,1933,1934],{"id":721,"depth":735,"text":721},{"id":838,"depth":735,"text":841,"children":1905},[1906],{"id":916,"depth":732,"text":919},{"id":943,"depth":735,"text":946,"children":1908},[1909,1910],{"id":1018,"depth":732,"text":1021},{"id":1063,"depth":732,"text":1066},{"id":1106,"depth":735,"text":1109,"children":1912},[1913,1914],{"id":1135,"depth":732,"text":1138},{"id":1224,"depth":732,"text":1227},{"id":1265,"depth":735,"text":1268,"children":1916},[1917,1918],{"id":1299,"depth":732,"text":1302},{"id":1333,"depth":732,"text":1336},{"id":1385,"depth":735,"text":1388,"children":1920},[1921,1922],{"id":1414,"depth":732,"text":1417},{"id":1490,"depth":732,"text":1493},{"id":1528,"depth":735,"text":1531,"children":1924},[1925,1926],{"id":1534,"depth":732,"text":1537},{"id":1558,"depth":732,"text":1561},{"id":1603,"depth":735,"text":1606},{"id":1679,"depth":735,"text":1682,"children":1929},[1930,1931,1932],{"id":1685,"depth":732,"text":1688},{"id":1729,"depth":732,"text":1732},{"id":1777,"depth":732,"text":1780},{"id":1804,"depth":735,"text":1807},{"id":1875,"depth":735,"text":1875},"content:topics:next:cache-strategy-deep-dive.md","topics/next/cache-strategy-deep-dive.md","topics/next/cache-strategy-deep-dive",{"_path":1939,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1940,"description":1941,"date":754,"topic":5,"author":11,"tags":1942,"image":1946,"featured":761,"readingTime":762,"body":1947,"_type":745,"_id":2745,"_source":747,"_file":2746,"_stem":2747,"_extension":750},"/topics/next/isr-practice","增量静态再生 (ISR) 实战","从缓存语义与一致性边界出发，讲清 ISR 的原理、适用场景与落地细节，并给出可直接复用的页面设计、失效策略与线上排障方法。",[13,1943,756,1944,1945],"ISR","SSG","SEO","/images/topics/next/isr.jpg",{"type":24,"children":1948,"toc":2720},[1949,1954,1959,1970,1975,1988,1993,2021,2024,2030,2035,2068,2073,2076,2082,2087,2100,2105,2118,2121,2127,2133,2138,2156,2161,2174,2180,2184,2202,2206,2224,2227,2233,2239,2244,2249,2262,2268,2273,2278,2291,2295,2308,2311,2317,2322,2327,2340,2345,2363,2366,2372,2377,2413,2418,2443,2448,2451,2457,2463,2468,2486,2492,2510,2516,2521,2539,2545,2558,2564,2577,2581,2594,2600,2605,2610,2623,2626,2632,2690,2693,2697,2702],{"type":27,"tag":28,"props":1950,"children":1952},{"id":1951},"增量静态再生-isr-实战",[1953],{"type":33,"value":1940},{"type":27,"tag":35,"props":1955,"children":1956},{},[1957],{"type":33,"value":1958},"ISR（Incremental Static Regeneration）经常被误解为“更聪明的 SSG”。",{"type":27,"tag":35,"props":1960,"children":1961},{},[1962,1964,1969],{"type":33,"value":1963},"更准确的说法是：ISR 是一套把“静态化收益”与“内容更新需求”折中起来的",{"type":27,"tag":775,"props":1965,"children":1966},{},[1967],{"type":33,"value":1968},"缓存与再生成协议",{"type":33,"value":781},{"type":27,"tag":35,"props":1971,"children":1972},{},[1973],{"type":33,"value":1974},"它解决的核心矛盾是：",{"type":27,"tag":345,"props":1976,"children":1977},{},[1978,1983],{"type":27,"tag":270,"props":1979,"children":1980},{},[1981],{"type":33,"value":1982},"你想要静态页面的性能与稳定性（低 TTFB、CDN 命中、高并发能力）",{"type":27,"tag":270,"props":1984,"children":1985},{},[1986],{"type":33,"value":1987},"你又希望内容能及时更新（分钟级甚至秒级）",{"type":27,"tag":35,"props":1989,"children":1990},{},[1991],{"type":33,"value":1992},"这篇文章按“上生产能跑稳”为标准，讲清：",{"type":27,"tag":345,"props":1994,"children":1995},{},[1996,2001,2006,2011,2016],{"type":27,"tag":270,"props":1997,"children":1998},{},[1999],{"type":33,"value":2000},"ISR 的工作原理与心智模型",{"type":27,"tag":270,"props":2002,"children":2003},{},[2004],{"type":33,"value":2005},"适用场景与反例",{"type":27,"tag":270,"props":2007,"children":2008},{},[2009],{"type":33,"value":2010},"页面设计（列表/详情/搜索）",{"type":27,"tag":270,"props":2012,"children":2013},{},[2014],{"type":33,"value":2015},"失效策略：时间驱动 vs 事件驱动",{"type":27,"tag":270,"props":2017,"children":2018},{},[2019],{"type":33,"value":2020},"线上排障：为什么更新不生效/为什么频繁回源",{"type":27,"tag":63,"props":2022,"children":2023},{},[],{"type":27,"tag":28,"props":2025,"children":2027},{"id":2026},"_1-先统一语言你到底想解决什么",[2028],{"type":33,"value":2029},"1. 先统一语言：你到底想解决什么？",{"type":27,"tag":35,"props":2031,"children":2032},{},[2033],{"type":33,"value":2034},"在真实业务里，“内容更新”通常有三种等级：",{"type":27,"tag":266,"props":2036,"children":2037},{},[2038,2048,2058],{"type":27,"tag":270,"props":2039,"children":2040},{},[2041,2046],{"type":27,"tag":775,"props":2042,"children":2043},{},[2044],{"type":33,"value":2045},"允许延迟",{"type":33,"value":2047},"：比如文章页、帮助文档、营销页，更新延迟 5~30 分钟都能接受",{"type":27,"tag":270,"props":2049,"children":2050},{},[2051,2056],{"type":27,"tag":775,"props":2052,"children":2053},{},[2054],{"type":33,"value":2055},"弱一致",{"type":33,"value":2057},"：比如商品价格、库存展示（可能需要更短 TTL，但可以接受短时间旧值）",{"type":27,"tag":270,"props":2059,"children":2060},{},[2061,2066],{"type":27,"tag":775,"props":2062,"children":2063},{},[2064],{"type":33,"value":2065},"强一致",{"type":33,"value":2067},"：比如支付结果、权限信息，不能用 ISR 兜底",{"type":27,"tag":35,"props":2069,"children":2070},{},[2071],{"type":33,"value":2072},"ISR 最适合第 1 类，谨慎用于第 2 类，不适合第 3 类。",{"type":27,"tag":63,"props":2074,"children":2075},{},[],{"type":27,"tag":28,"props":2077,"children":2079},{"id":2078},"_2-isr-的心智模型把它当成cdn-后的再生成缓存",[2080],{"type":33,"value":2081},"2. ISR 的心智模型：把它当成“CDN 后的再生成缓存”",{"type":27,"tag":35,"props":2083,"children":2084},{},[2085],{"type":33,"value":2086},"你可以把 ISR 看作两层：",{"type":27,"tag":345,"props":2088,"children":2089},{},[2090,2095],{"type":27,"tag":270,"props":2091,"children":2092},{},[2093],{"type":33,"value":2094},"CDN：缓存最终 HTML（或 RSC payload）",{"type":27,"tag":270,"props":2096,"children":2097},{},[2098],{"type":33,"value":2099},"应用（Next.js）：缓存页面生成结果，并按规则触发再生成",{"type":27,"tag":35,"props":2101,"children":2102},{},[2103],{"type":33,"value":2104},"关键点：",{"type":27,"tag":345,"props":2106,"children":2107},{},[2108,2113],{"type":27,"tag":270,"props":2109,"children":2110},{},[2111],{"type":33,"value":2112},"ISR 不是“每次请求都重新生成”，而是“绝大多数时候直接命中缓存”",{"type":27,"tag":270,"props":2114,"children":2115},{},[2116],{"type":33,"value":2117},"再生成是“受控发生”的",{"type":27,"tag":63,"props":2119,"children":2120},{},[],{"type":27,"tag":28,"props":2122,"children":2124},{"id":2123},"_3-两种驱动方式时间驱动-vs-事件驱动",[2125],{"type":33,"value":2126},"3. 两种驱动方式：时间驱动 vs 事件驱动",{"type":27,"tag":914,"props":2128,"children":2130},{"id":2129},"_31-时间驱动revalidate-秒数",[2131],{"type":33,"value":2132},"3.1 时间驱动（revalidate 秒数）",{"type":27,"tag":35,"props":2134,"children":2135},{},[2136],{"type":33,"value":2137},"特点：",{"type":27,"tag":345,"props":2139,"children":2140},{},[2141,2146,2151],{"type":27,"tag":270,"props":2142,"children":2143},{},[2144],{"type":33,"value":2145},"简单",{"type":27,"tag":270,"props":2147,"children":2148},{},[2149],{"type":33,"value":2150},"稳定",{"type":27,"tag":270,"props":2152,"children":2153},{},[2154],{"type":33,"value":2155},"但更新延迟不可控（取决于 TTL 与访问触发）",{"type":27,"tag":35,"props":2157,"children":2158},{},[2159],{"type":33,"value":2160},"适用：",{"type":27,"tag":345,"props":2162,"children":2163},{},[2164,2169],{"type":27,"tag":270,"props":2165,"children":2166},{},[2167],{"type":33,"value":2168},"内容更新不频繁",{"type":27,"tag":270,"props":2170,"children":2171},{},[2172],{"type":33,"value":2173},"不需要“发布即生效”",{"type":27,"tag":914,"props":2175,"children":2177},{"id":2176},"_32-事件驱动按需再验证-webhook",[2178],{"type":33,"value":2179},"3.2 事件驱动（按需再验证 / webhook）",{"type":27,"tag":35,"props":2181,"children":2182},{},[2183],{"type":33,"value":2137},{"type":27,"tag":345,"props":2185,"children":2186},{},[2187,2192,2197],{"type":27,"tag":270,"props":2188,"children":2189},{},[2190],{"type":33,"value":2191},"发布后可快速生效",{"type":27,"tag":270,"props":2193,"children":2194},{},[2195],{"type":33,"value":2196},"更可控",{"type":27,"tag":270,"props":2198,"children":2199},{},[2200],{"type":33,"value":2201},"需要你有“内容发布事件”与安全机制",{"type":27,"tag":35,"props":2203,"children":2204},{},[2205],{"type":33,"value":2160},{"type":27,"tag":345,"props":2207,"children":2208},{},[2209,2214,2219],{"type":27,"tag":270,"props":2210,"children":2211},{},[2212],{"type":33,"value":2213},"CMS 发布文章",{"type":27,"tag":270,"props":2215,"children":2216},{},[2217],{"type":33,"value":2218},"商品信息变更",{"type":27,"tag":270,"props":2220,"children":2221},{},[2222],{"type":33,"value":2223},"专题页更新",{"type":27,"tag":63,"props":2225,"children":2226},{},[],{"type":27,"tag":28,"props":2228,"children":2230},{"id":2229},"_4-典型页面怎么做列表-详情",[2231],{"type":33,"value":2232},"4. 典型页面怎么做：列表 + 详情",{"type":27,"tag":914,"props":2234,"children":2236},{"id":2235},"_41-详情页优先事件驱动",[2237],{"type":33,"value":2238},"4.1 详情页：优先事件驱动",{"type":27,"tag":35,"props":2240,"children":2241},{},[2242],{"type":33,"value":2243},"详情页更新的最佳体验通常是“发布即生效”。",{"type":27,"tag":35,"props":2245,"children":2246},{},[2247],{"type":33,"value":2248},"策略：",{"type":27,"tag":345,"props":2250,"children":2251},{},[2252,2257],{"type":27,"tag":270,"props":2253,"children":2254},{},[2255],{"type":33,"value":2256},"详情页使用 ISR（或静态 + 按需再验证）",{"type":27,"tag":270,"props":2258,"children":2259},{},[2260],{"type":33,"value":2261},"CMS 发布时调用 webhook，让应用对特定 path/tag 失效",{"type":27,"tag":914,"props":2263,"children":2265},{"id":2264},"_42-列表页注意聚合页放大效应",[2266],{"type":33,"value":2267},"4.2 列表页：注意“聚合页放大效应”",{"type":27,"tag":35,"props":2269,"children":2270},{},[2271],{"type":33,"value":2272},"列表页（例如文章列表、商品列表）会被大量访问，且它的内容聚合了很多详情。",{"type":27,"tag":35,"props":2274,"children":2275},{},[2276],{"type":33,"value":2277},"常见坑：",{"type":27,"tag":345,"props":2279,"children":2280},{},[2281,2286],{"type":27,"tag":270,"props":2282,"children":2283},{},[2284],{"type":33,"value":2285},"每次新增一篇文章都要失效列表页",{"type":27,"tag":270,"props":2287,"children":2288},{},[2289],{"type":33,"value":2290},"导致列表页频繁再生成 → 回源增多",{"type":27,"tag":35,"props":2292,"children":2293},{},[2294],{"type":33,"value":1232},{"type":27,"tag":345,"props":2296,"children":2297},{},[2298,2303],{"type":27,"tag":270,"props":2299,"children":2300},{},[2301],{"type":33,"value":2302},"列表页采用较长 TTL（例如 10~30 分钟）",{"type":27,"tag":270,"props":2304,"children":2305},{},[2306],{"type":33,"value":2307},"或把“最新内容”拆成单独模块，使用客户端请求/边缘 KV",{"type":27,"tag":63,"props":2309,"children":2310},{},[],{"type":27,"tag":28,"props":2312,"children":2314},{"id":2313},"_5-数据获取与缓存别把-isr-做成慢-ssr",[2315],{"type":33,"value":2316},"5. 数据获取与缓存：别把 ISR 做成“慢 SSR”",{"type":27,"tag":35,"props":2318,"children":2319},{},[2320],{"type":33,"value":2321},"ISR 的性能收益来自“生成一次 → 复用很多次”。",{"type":27,"tag":35,"props":2323,"children":2324},{},[2325],{"type":33,"value":2326},"所以你要避免：",{"type":27,"tag":345,"props":2328,"children":2329},{},[2330,2335],{"type":27,"tag":270,"props":2331,"children":2332},{},[2333],{"type":33,"value":2334},"页面生成时做大量慢查询",{"type":27,"tag":270,"props":2336,"children":2337},{},[2338],{"type":33,"value":2339},"页面生成时串行请求多个上游",{"type":27,"tag":35,"props":2341,"children":2342},{},[2343],{"type":33,"value":2344},"实践建议：",{"type":27,"tag":345,"props":2346,"children":2347},{},[2348,2353,2358],{"type":27,"tag":270,"props":2349,"children":2350},{},[2351],{"type":33,"value":2352},"生成路径尽量轻（prefetch、批量接口、缓存）",{"type":27,"tag":270,"props":2354,"children":2355},{},[2356],{"type":33,"value":2357},"对上游请求设置超时",{"type":27,"tag":270,"props":2359,"children":2360},{},[2361],{"type":33,"value":2362},"做并行请求",{"type":27,"tag":63,"props":2364,"children":2365},{},[],{"type":27,"tag":28,"props":2367,"children":2369},{"id":2368},"_6-失效策略设计从靠感觉到有规则",[2370],{"type":33,"value":2371},"6. 失效策略设计：从“靠感觉”到“有规则”",{"type":27,"tag":35,"props":2373,"children":2374},{},[2375],{"type":33,"value":2376},"建议采用“域驱动失效”思路：",{"type":27,"tag":345,"props":2378,"children":2379},{},[2380,2391,2402],{"type":27,"tag":270,"props":2381,"children":2382},{},[2383,2385],{"type":33,"value":2384},"文章：",{"type":27,"tag":41,"props":2386,"children":2388},{"className":2387},[],[2389],{"type":33,"value":2390},"article:{slug}",{"type":27,"tag":270,"props":2392,"children":2393},{},[2394,2396],{"type":33,"value":2395},"文章列表：",{"type":27,"tag":41,"props":2397,"children":2399},{"className":2398},[],[2400],{"type":33,"value":2401},"article:list",{"type":27,"tag":270,"props":2403,"children":2404},{},[2405,2407],{"type":33,"value":2406},"专题：",{"type":27,"tag":41,"props":2408,"children":2410},{"className":2409},[],[2411],{"type":33,"value":2412},"topic:{name}",{"type":27,"tag":35,"props":2414,"children":2415},{},[2416],{"type":33,"value":2417},"当某篇文章更新：",{"type":27,"tag":345,"props":2419,"children":2420},{},[2421,2431],{"type":27,"tag":270,"props":2422,"children":2423},{},[2424,2426],{"type":33,"value":2425},"必失效：",{"type":27,"tag":41,"props":2427,"children":2429},{"className":2428},[],[2430],{"type":33,"value":2390},{"type":27,"tag":270,"props":2432,"children":2433},{},[2434,2436,2441],{"type":33,"value":2435},"可选失效：",{"type":27,"tag":41,"props":2437,"children":2439},{"className":2438},[],[2440],{"type":33,"value":2401},{"type":33,"value":2442},"（看你是否要求“列表立即出现最新文章”）",{"type":27,"tag":35,"props":2444,"children":2445},{},[2446],{"type":33,"value":2447},"这样你能解释每一次失效，而不是“全站清缓存”。",{"type":27,"tag":63,"props":2449,"children":2450},{},[],{"type":27,"tag":28,"props":2452,"children":2454},{"id":2453},"_7-线上排障isr-最常见的-6-个问题",[2455],{"type":33,"value":2456},"7. 线上排障：ISR 最常见的 6 个问题",{"type":27,"tag":914,"props":2458,"children":2460},{"id":2459},"_71-发布了但页面不更新",[2461],{"type":33,"value":2462},"7.1 “发布了但页面不更新”",{"type":27,"tag":35,"props":2464,"children":2465},{},[2466],{"type":33,"value":2467},"排查顺序：",{"type":27,"tag":345,"props":2469,"children":2470},{},[2471,2476,2481],{"type":27,"tag":270,"props":2472,"children":2473},{},[2474],{"type":33,"value":2475},"webhook 是否触发？是否被鉴权拦截？",{"type":27,"tag":270,"props":2477,"children":2478},{},[2479],{"type":33,"value":2480},"失效的是正确的 path/tag 吗？",{"type":27,"tag":270,"props":2482,"children":2483},{},[2484],{"type":33,"value":2485},"CDN 是否仍在强缓存旧内容？（看响应头、Cache-Status）",{"type":27,"tag":914,"props":2487,"children":2489},{"id":2488},"_72-页面更新了但-seo-抓不到",[2490],{"type":33,"value":2491},"7.2 “页面更新了但 SEO 抓不到”",{"type":27,"tag":345,"props":2493,"children":2494},{},[2495,2500,2505],{"type":27,"tag":270,"props":2496,"children":2497},{},[2498],{"type":33,"value":2499},"sitemap 是否更新",{"type":27,"tag":270,"props":2501,"children":2502},{},[2503],{"type":33,"value":2504},"canonical/robots 是否正确",{"type":27,"tag":270,"props":2506,"children":2507},{},[2508],{"type":33,"value":2509},"是否把重要内容放在客户端渲染",{"type":27,"tag":914,"props":2511,"children":2513},{"id":2512},"_73-回源突然暴增",[2514],{"type":33,"value":2515},"7.3 “回源突然暴增”",{"type":27,"tag":35,"props":2517,"children":2518},{},[2519],{"type":33,"value":2520},"常见原因：",{"type":27,"tag":345,"props":2522,"children":2523},{},[2524,2529,2534],{"type":27,"tag":270,"props":2525,"children":2526},{},[2527],{"type":33,"value":2528},"TTL 设太短",{"type":27,"tag":270,"props":2530,"children":2531},{},[2532],{"type":33,"value":2533},"聚合页频繁失效",{"type":27,"tag":270,"props":2535,"children":2536},{},[2537],{"type":33,"value":2538},"缓存命中率被 query 污染（utm）",{"type":27,"tag":914,"props":2540,"children":2542},{"id":2541},"_74-某些地区更新很慢",[2543],{"type":33,"value":2544},"7.4 “某些地区更新很慢”",{"type":27,"tag":345,"props":2546,"children":2547},{},[2548,2553],{"type":27,"tag":270,"props":2549,"children":2550},{},[2551],{"type":33,"value":2552},"CDN 分区缓存",{"type":27,"tag":270,"props":2554,"children":2555},{},[2556],{"type":33,"value":2557},"边缘节点回源延迟",{"type":27,"tag":914,"props":2559,"children":2561},{"id":2560},"_75-低峰正常高峰崩",[2562],{"type":33,"value":2563},"7.5 “低峰正常，高峰崩”",{"type":27,"tag":345,"props":2565,"children":2566},{},[2567,2572],{"type":27,"tag":270,"props":2568,"children":2569},{},[2570],{"type":33,"value":2571},"再生成并发过高",{"type":27,"tag":270,"props":2573,"children":2574},{},[2575],{"type":33,"value":2576},"上游服务扛不住",{"type":27,"tag":35,"props":2578,"children":2579},{},[2580],{"type":33,"value":2248},{"type":27,"tag":345,"props":2582,"children":2583},{},[2584,2589],{"type":27,"tag":270,"props":2585,"children":2586},{},[2587],{"type":33,"value":2588},"限制再生成并发",{"type":27,"tag":270,"props":2590,"children":2591},{},[2592],{"type":33,"value":2593},"对再生成做队列化",{"type":27,"tag":914,"props":2595,"children":2597},{"id":2596},"_76-用户态数据被缓存",[2598],{"type":33,"value":2599},"7.6 “用户态数据被缓存”",{"type":27,"tag":35,"props":2601,"children":2602},{},[2603],{"type":33,"value":2604},"这是最危险的。",{"type":27,"tag":35,"props":2606,"children":2607},{},[2608],{"type":33,"value":2609},"规则：",{"type":27,"tag":345,"props":2611,"children":2612},{},[2613,2618],{"type":27,"tag":270,"props":2614,"children":2615},{},[2616],{"type":33,"value":2617},"用户态页面不要 ISR",{"type":27,"tag":270,"props":2619,"children":2620},{},[2621],{"type":33,"value":2622},"或把私有信息拆出（客户端请求）",{"type":27,"tag":63,"props":2624,"children":2625},{},[],{"type":27,"tag":28,"props":2627,"children":2629},{"id":2628},"_8-上线检查清单",[2630],{"type":33,"value":2631},"8. 上线检查清单",{"type":27,"tag":345,"props":2633,"children":2635},{"className":2634},[1811],[2636,2645,2654,2663,2672,2681],{"type":27,"tag":270,"props":2637,"children":2639},{"className":2638},[1816],[2640,2643],{"type":27,"tag":1819,"props":2641,"children":2642},{"disabled":761,"type":1821},[],{"type":33,"value":2644}," 哪些路由使用 ISR？是否排除用户态页面",{"type":27,"tag":270,"props":2646,"children":2648},{"className":2647},[1816],[2649,2652],{"type":27,"tag":1819,"props":2650,"children":2651},{"disabled":761,"type":1821},[],{"type":33,"value":2653}," 详情页与列表页的 TTL 是否合理",{"type":27,"tag":270,"props":2655,"children":2657},{"className":2656},[1816],[2658,2661],{"type":27,"tag":1819,"props":2659,"children":2660},{"disabled":761,"type":1821},[],{"type":33,"value":2662}," 是否有事件驱动失效（CMS webhook）",{"type":27,"tag":270,"props":2664,"children":2666},{"className":2665},[1816],[2667,2670],{"type":27,"tag":1819,"props":2668,"children":2669},{"disabled":761,"type":1821},[],{"type":33,"value":2671}," CDN cache key 是否会被 query 污染",{"type":27,"tag":270,"props":2673,"children":2675},{"className":2674},[1816],[2676,2679],{"type":27,"tag":1819,"props":2677,"children":2678},{"disabled":761,"type":1821},[],{"type":33,"value":2680}," 是否有命中率/回源/QPS 监控",{"type":27,"tag":270,"props":2682,"children":2684},{"className":2683},[1816],[2685,2688],{"type":27,"tag":1819,"props":2686,"children":2687},{"disabled":761,"type":1821},[],{"type":33,"value":2689}," 再生成失败是否可观测（日志、报警）",{"type":27,"tag":63,"props":2691,"children":2692},{},[],{"type":27,"tag":28,"props":2694,"children":2695},{"id":1875},[2696],{"type":33,"value":1875},{"type":27,"tag":35,"props":2698,"children":2699},{},[2700],{"type":33,"value":2701},"ISR 的正确用法是：",{"type":27,"tag":345,"props":2703,"children":2704},{},[2705,2710,2715],{"type":27,"tag":270,"props":2706,"children":2707},{},[2708],{"type":33,"value":2709},"把它当成“带可控失效的静态缓存系统”",{"type":27,"tag":270,"props":2711,"children":2712},{},[2713],{"type":33,"value":2714},"用规则设计失效，而不是全站清缓存",{"type":27,"tag":270,"props":2716,"children":2717},{},[2718],{"type":33,"value":2719},"用监控保证它在高峰依然稳定",{"title":7,"searchDepth":732,"depth":732,"links":2721},[2722,2723,2724,2725,2729,2733,2734,2735,2743,2744],{"id":1951,"depth":735,"text":1940},{"id":2026,"depth":735,"text":2029},{"id":2078,"depth":735,"text":2081},{"id":2123,"depth":735,"text":2126,"children":2726},[2727,2728],{"id":2129,"depth":732,"text":2132},{"id":2176,"depth":732,"text":2179},{"id":2229,"depth":735,"text":2232,"children":2730},[2731,2732],{"id":2235,"depth":732,"text":2238},{"id":2264,"depth":732,"text":2267},{"id":2313,"depth":735,"text":2316},{"id":2368,"depth":735,"text":2371},{"id":2453,"depth":735,"text":2456,"children":2736},[2737,2738,2739,2740,2741,2742],{"id":2459,"depth":732,"text":2462},{"id":2488,"depth":732,"text":2491},{"id":2512,"depth":732,"text":2515},{"id":2541,"depth":732,"text":2544},{"id":2560,"depth":732,"text":2563},{"id":2596,"depth":732,"text":2599},{"id":2628,"depth":735,"text":2631},{"id":1875,"depth":735,"text":1875},"content:topics:next:isr-practice.md","topics/next/isr-practice.md","topics/next/isr-practice",{"_path":709,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":712,"description":2749,"date":754,"topic":5,"author":11,"tags":2750,"image":2754,"featured":761,"readingTime":2755,"body":2756,"_type":745,"_id":3865,"_source":747,"_file":3866,"_stem":3867,"_extension":750},"从工作原理到安全边界与缓存语义，系统讲透 Next.js Server Actions 的编程模型，并给出可直接落地的工程化实践范式。",[13,2751,14,2752,2753,756],"Server Actions","表单","安全","/images/topics/next/server-actions.jpg",20,{"type":24,"children":2757,"toc":3831},[2758,2763,2774,2786,2791,2830,2833,2839,2844,2857,2862,2895,2900,2918,2930,2933,2939,2952,2957,2988,2993,3016,3022,3027,3032,3050,3071,3074,3080,3086,3091,3100,3105,3114,3119,3137,3143,3152,3157,3175,3178,3184,3189,3225,3230,3239,3248,3257,3262,3280,3283,3289,3294,3305,3311,3316,3329,3338,3344,3357,3362,3368,3373,3378,3410,3416,3421,3442,3448,3453,3457,3470,3473,3479,3484,3489,3522,3528,3552,3557,3581,3592,3597,3602,3615,3618,3624,3638,3643,3661,3667,3672,3690,3695,3698,3704,3722,3727,3730,3736,3741,3799,3802,3808,3813],{"type":27,"tag":28,"props":2759,"children":2761},{"id":2760},"server-actions-完整指南",[2762],{"type":33,"value":712},{"type":27,"tag":35,"props":2764,"children":2765},{},[2766,2768,2773],{"type":33,"value":2767},"Server Actions 是 Next.js（App Router 体系）里最有“范式转移”意味的能力之一：它把“从浏览器提交数据 → 走 API → 服务端写库 → 客户端再拉取数据”这条链路，压缩成",{"type":27,"tag":775,"props":2769,"children":2770},{},[2771],{"type":33,"value":2772},"在 UI 里直接调用一个服务端函数",{"type":33,"value":781},{"type":27,"tag":35,"props":2775,"children":2776},{},[2777,2779,2784],{"type":33,"value":2778},"但它并不是“把后端写进前端”，而是一套围绕 ",{"type":27,"tag":775,"props":2780,"children":2781},{},[2782],{"type":33,"value":2783},"RSC（React Server Components）边界、请求序列化、缓存与失效、安全隔离",{"type":33,"value":2785}," 重新定义的交互协议。",{"type":27,"tag":35,"props":2787,"children":2788},{},[2789],{"type":33,"value":2790},"这篇文章按“能在生产落地”为标准，依次讲清：",{"type":27,"tag":345,"props":2792,"children":2793},{},[2794,2799,2810,2815,2820,2825],{"type":27,"tag":270,"props":2795,"children":2796},{},[2797],{"type":33,"value":2798},"什么时候该用/不该用 Server Actions",{"type":27,"tag":270,"props":2800,"children":2801},{},[2802,2808],{"type":27,"tag":41,"props":2803,"children":2805},{"className":2804},[],[2806],{"type":33,"value":2807},"'use server'",{"type":33,"value":2809}," 的语义与编译期边界",{"type":27,"tag":270,"props":2811,"children":2812},{},[2813],{"type":33,"value":2814},"表单提交、并发与幂等",{"type":27,"tag":270,"props":2816,"children":2817},{},[2818],{"type":33,"value":2819},"权限、校验、CSRF/重放、敏感信息",{"type":27,"tag":270,"props":2821,"children":2822},{},[2823],{"type":33,"value":2824},"缓存与 revalidate 的正确打开方式",{"type":27,"tag":270,"props":2826,"children":2827},{},[2828],{"type":33,"value":2829},"一套可复用的工程化结构（Action 层、schema、错误码）",{"type":27,"tag":63,"props":2831,"children":2832},{},[],{"type":27,"tag":28,"props":2834,"children":2836},{"id":2835},"_1-server-actions-解决的到底是什么问题",[2837],{"type":33,"value":2838},"1. Server Actions 解决的到底是什么问题？",{"type":27,"tag":35,"props":2840,"children":2841},{},[2842],{"type":33,"value":2843},"在传统前端架构里，“写操作”通常需要两套代码：",{"type":27,"tag":266,"props":2845,"children":2846},{},[2847,2852],{"type":27,"tag":270,"props":2848,"children":2849},{},[2850],{"type":33,"value":2851},"UI 层构造请求（fetch/axios）",{"type":27,"tag":270,"props":2853,"children":2854},{},[2855],{"type":33,"value":2856},"API 层解析请求、校验、执行业务",{"type":27,"tag":35,"props":2858,"children":2859},{},[2860],{"type":33,"value":2861},"这导致三个常见痛点：",{"type":27,"tag":345,"props":2863,"children":2864},{},[2865,2875,2885],{"type":27,"tag":270,"props":2866,"children":2867},{},[2868,2873],{"type":27,"tag":775,"props":2869,"children":2870},{},[2871],{"type":33,"value":2872},"样板代码多",{"type":33,"value":2874},"：DTO、路由、controller、错误映射",{"type":27,"tag":270,"props":2876,"children":2877},{},[2878,2883],{"type":27,"tag":775,"props":2879,"children":2880},{},[2881],{"type":33,"value":2882},"类型不一致",{"type":33,"value":2884},"：前后端 schema 漂移，靠约定或手写 types",{"type":27,"tag":270,"props":2886,"children":2887},{},[2888,2893],{"type":27,"tag":775,"props":2889,"children":2890},{},[2891],{"type":33,"value":2892},"缓存/失效复杂",{"type":33,"value":2894},"：写完数据后，页面该怎么更新？哪些缓存该失效？",{"type":27,"tag":35,"props":2896,"children":2897},{},[2898],{"type":33,"value":2899},"Server Actions 的核心价值是：",{"type":27,"tag":345,"props":2901,"children":2902},{},[2903,2913],{"type":27,"tag":270,"props":2904,"children":2905},{},[2906,2911],{"type":27,"tag":775,"props":2907,"children":2908},{},[2909],{"type":33,"value":2910},"把“写操作”收敛成一个服务端函数",{"type":33,"value":2912},"，由框架负责把调用从 client 路由到 server；",{"type":27,"tag":270,"props":2914,"children":2915},{},[2916],{"type":33,"value":2917},"在 App Router 的缓存语义下，提供与页面缓存/请求缓存更一致的“失效”手段。",{"type":27,"tag":35,"props":2919,"children":2920},{},[2921,2923,2928],{"type":33,"value":2922},"你可以把它理解为：Next.js 给“写操作”提供了一个",{"type":27,"tag":775,"props":2924,"children":2925},{},[2926],{"type":33,"value":2927},"与 RSC/缓存模型原生兼容",{"type":33,"value":2929},"的调用入口。",{"type":27,"tag":63,"props":2931,"children":2932},{},[],{"type":27,"tag":28,"props":2934,"children":2936},{"id":2935},"_2-心智模型server-actions-与-rsc-的边界",[2937],{"type":33,"value":2938},"2. 心智模型：Server Actions 与 RSC 的边界",{"type":27,"tag":914,"props":2940,"children":2942},{"id":2941},"_21-use-server-不是运行时开关而是编译期边界",[2943,2945,2950],{"type":33,"value":2944},"2.1 ",{"type":27,"tag":41,"props":2946,"children":2948},{"className":2947},[],[2949],{"type":33,"value":2807},{"type":33,"value":2951}," 不是运行时开关，而是编译期边界",{"type":27,"tag":35,"props":2953,"children":2954},{},[2955],{"type":33,"value":2956},"在 Next.js 中：",{"type":27,"tag":345,"props":2958,"children":2959},{},[2960,2983],{"type":27,"tag":270,"props":2961,"children":2962},{},[2963,2969,2970,2975,2977,2982],{"type":27,"tag":41,"props":2964,"children":2966},{"className":2965},[],[2967],{"type":33,"value":2968},"'use client'",{"type":33,"value":965},{"type":27,"tag":41,"props":2971,"children":2973},{"className":2972},[],[2974],{"type":33,"value":2807},{"type":33,"value":2976}," 是",{"type":27,"tag":775,"props":2978,"children":2979},{},[2980],{"type":33,"value":2981},"模块级/函数级的编译指令",{"type":33,"value":781},{"type":27,"tag":270,"props":2984,"children":2985},{},[2986],{"type":33,"value":2987},"被标记为 Server Action 的函数只能在服务端执行；在客户端调用时，框架会生成一个“可调用的引用”，最终由服务端执行。",{"type":27,"tag":35,"props":2989,"children":2990},{},[2991],{"type":33,"value":2992},"一个直观的理解：",{"type":27,"tag":345,"props":2994,"children":2995},{},[2996,3006],{"type":27,"tag":270,"props":2997,"children":2998},{},[2999,3004],{"type":27,"tag":775,"props":3000,"children":3001},{},[3002],{"type":33,"value":3003},"你写的是函数",{"type":33,"value":3005},"；",{"type":27,"tag":270,"props":3007,"children":3008},{},[3009,3014],{"type":27,"tag":775,"props":3010,"children":3011},{},[3012],{"type":33,"value":3013},"框架生成的是 RPC",{"type":33,"value":3015},"（带序列化、鉴权/上下文、执行、返回）。",{"type":27,"tag":914,"props":3017,"children":3019},{"id":3018},"_22-传参限制可序列化是第一原则",[3020],{"type":33,"value":3021},"2.2 传参限制：可序列化是第一原则",{"type":27,"tag":35,"props":3023,"children":3024},{},[3025],{"type":33,"value":3026},"Server Action 的参数需要能安全序列化。",{"type":27,"tag":35,"props":3028,"children":3029},{},[3030],{"type":33,"value":3031},"建议遵循：",{"type":27,"tag":345,"props":3033,"children":3034},{},[3035,3045],{"type":27,"tag":270,"props":3036,"children":3037},{},[3038,3040],{"type":33,"value":3039},"只传 ",{"type":27,"tag":775,"props":3041,"children":3042},{},[3043],{"type":33,"value":3044},"primitive / plain object / array / FormData",{"type":27,"tag":270,"props":3046,"children":3047},{},[3048],{"type":33,"value":3049},"不传 class 实例、函数、DOM 节点、复杂原型对象",{"type":27,"tag":35,"props":3051,"children":3052},{},[3053,3055,3061,3063,3069],{"type":33,"value":3054},"如果你发现自己想把“整个业务对象”丢进去，通常意味着你应该传一个 ",{"type":27,"tag":41,"props":3056,"children":3058},{"className":3057},[],[3059],{"type":33,"value":3060},"id",{"type":33,"value":3062}," 或 ",{"type":27,"tag":41,"props":3064,"children":3066},{"className":3065},[],[3067],{"type":33,"value":3068},"payload",{"type":33,"value":3070},"，然后在服务端再查询/校验。",{"type":27,"tag":63,"props":3072,"children":3073},{},[],{"type":27,"tag":28,"props":3075,"children":3077},{"id":3076},"_3-两种主流用法表单-action-与事件-action",[3078],{"type":33,"value":3079},"3. 两种主流用法：表单 Action 与事件 Action",{"type":27,"tag":914,"props":3081,"children":3083},{"id":3082},"_31-表单提交推荐天然-csrf-友好契合-web-标准",[3084],{"type":33,"value":3085},"3.1 表单提交（推荐）：天然 CSRF 友好，契合 Web 标准",{"type":27,"tag":35,"props":3087,"children":3088},{},[3089],{"type":33,"value":3090},"Server Actions 最推荐的入口是表单：",{"type":27,"tag":201,"props":3092,"children":3095},{"className":3093,"code":3094,"language":206,"meta":7},[204],"// app/settings/page.tsx\nimport { updateProfileAction } from './actions'\n\nexport default function SettingsPage() {\n  return (\n    \u003Cform action={updateProfileAction}>\n      \u003Cinput name=\"displayName\" />\n      \u003Cbutton type=\"submit\">保存\u003C/button>\n    \u003C/form>\n  )\n}\n",[3096],{"type":27,"tag":41,"props":3097,"children":3098},{"__ignoreMap":7},[3099],{"type":33,"value":3094},{"type":27,"tag":35,"props":3101,"children":3102},{},[3103],{"type":33,"value":3104},"在服务端：",{"type":27,"tag":201,"props":3106,"children":3109},{"className":3107,"code":3108,"language":593,"meta":7},[591],"// app/settings/actions.ts\n'use server'\n\nexport async function updateProfileAction(formData: FormData) {\n  const displayName = String(formData.get('displayName') || '').trim()\n  // 校验、鉴权、写库...\n}\n",[3110],{"type":27,"tag":41,"props":3111,"children":3112},{"__ignoreMap":7},[3113],{"type":33,"value":3108},{"type":27,"tag":35,"props":3115,"children":3116},{},[3117],{"type":33,"value":3118},"为什么推荐表单？",{"type":27,"tag":345,"props":3120,"children":3121},{},[3122,3127,3132],{"type":27,"tag":270,"props":3123,"children":3124},{},[3125],{"type":33,"value":3126},"浏览器原生语义：回退/刷新更自然",{"type":27,"tag":270,"props":3128,"children":3129},{},[3130],{"type":33,"value":3131},"你更容易把“输入 → 校验 → 保存”做成明确的流水线",{"type":27,"tag":270,"props":3133,"children":3134},{},[3135],{"type":33,"value":3136},"比“按钮 onClick 调 action”更不容易写出隐式并发 bug",{"type":27,"tag":914,"props":3138,"children":3140},{"id":3139},"_32-事件触发慎用更像-rpc必须处理并发与幂等",[3141],{"type":33,"value":3142},"3.2 事件触发（慎用）：更像 RPC，必须处理并发与幂等",{"type":27,"tag":201,"props":3144,"children":3147},{"className":3145,"code":3146,"language":206,"meta":7},[204],"'use client'\nimport { toggleStarAction } from './actions'\n\nexport function StarButton({ id }: { id: string }) {\n  return (\n    \u003Cbutton\n      onClick={async () => {\n        await toggleStarAction(id)\n      }}\n    >\n      Star\n    \u003C/button>\n  )\n}\n",[3148],{"type":27,"tag":41,"props":3149,"children":3150},{"__ignoreMap":7},[3151],{"type":33,"value":3146},{"type":27,"tag":35,"props":3153,"children":3154},{},[3155],{"type":33,"value":3156},"这类用法更像“客户端发起 RPC”，你需要格外注意：",{"type":27,"tag":345,"props":3158,"children":3159},{},[3160,3165,3170],{"type":27,"tag":270,"props":3161,"children":3162},{},[3163],{"type":33,"value":3164},"重复点击导致并发",{"type":27,"tag":270,"props":3166,"children":3167},{},[3168],{"type":33,"value":3169},"网络抖动导致重试",{"type":27,"tag":270,"props":3171,"children":3172},{},[3173],{"type":33,"value":3174},"乐观更新与最终一致",{"type":27,"tag":63,"props":3176,"children":3177},{},[],{"type":27,"tag":28,"props":3179,"children":3181},{"id":3180},"_4-工程化落地action-层应该长什么样",[3182],{"type":33,"value":3183},"4. 工程化落地：Action 层应该长什么样？",{"type":27,"tag":35,"props":3185,"children":3186},{},[3187],{"type":33,"value":3188},"一个能长期维护的结构，通常把“Action 的对外接口”与“业务实现”分离：",{"type":27,"tag":345,"props":3190,"children":3191},{},[3192,3203,3214],{"type":27,"tag":270,"props":3193,"children":3194},{},[3195,3201],{"type":27,"tag":41,"props":3196,"children":3198},{"className":3197},[],[3199],{"type":33,"value":3200},"actions/*.ts",{"type":33,"value":3202},"：只负责输入解析、校验、鉴权、错误映射、触发失效",{"type":27,"tag":270,"props":3204,"children":3205},{},[3206,3212],{"type":27,"tag":41,"props":3207,"children":3209},{"className":3208},[],[3210],{"type":33,"value":3211},"services/*.ts",{"type":33,"value":3213},"：纯业务逻辑（可被 API/任务队列复用）",{"type":27,"tag":270,"props":3215,"children":3216},{},[3217,3223],{"type":27,"tag":41,"props":3218,"children":3220},{"className":3219},[],[3221],{"type":33,"value":3222},"schemas/*.ts",{"type":33,"value":3224},"：输入 schema（建议用 zod 或你们统一的校验工具）",{"type":27,"tag":35,"props":3226,"children":3227},{},[3228],{"type":33,"value":3229},"示例：",{"type":27,"tag":201,"props":3231,"children":3234},{"className":3232,"code":3233,"language":593,"meta":7},[591],"// app/settings/schemas.ts\nimport { z } from 'zod'\n\nexport const updateProfileSchema = z.object({\n  displayName: z.string().min(2).max(32),\n})\n",[3235],{"type":27,"tag":41,"props":3236,"children":3237},{"__ignoreMap":7},[3238],{"type":33,"value":3233},{"type":27,"tag":201,"props":3240,"children":3243},{"className":3241,"code":3242,"language":593,"meta":7},[591],"// app/settings/services.ts\nexport async function updateProfile(userId: string, input: { displayName: string }) {\n  // 写库、写缓存、发事件...\n}\n",[3244],{"type":27,"tag":41,"props":3245,"children":3246},{"__ignoreMap":7},[3247],{"type":33,"value":3242},{"type":27,"tag":201,"props":3249,"children":3252},{"className":3250,"code":3251,"language":593,"meta":7},[591],"// app/settings/actions.ts\n'use server'\n\nimport { updateProfileSchema } from './schemas'\nimport { updateProfile } from './services'\nimport { revalidatePath } from 'next/cache'\n\nclass ActionError extends Error {\n  code: string\n  constructor(code: string, message: string) {\n    super(message)\n    this.code = code\n  }\n}\n\nfunction requireUserId(): string {\n  // 伪代码：从会话中拿 user\n  // const user = await auth()\n  // if (!user) throw new ActionError('UNAUTHORIZED', '请先登录')\n  return 'user_123'\n}\n\nexport async function updateProfileAction(formData: FormData) {\n  const userId = requireUserId()\n\n  const input = {\n    displayName: String(formData.get('displayName') || '').trim(),\n  }\n\n  const parsed = updateProfileSchema.safeParse(input)\n  if (!parsed.success) {\n    throw new ActionError('VALIDATION_ERROR', '输入不合法')\n  }\n\n  await updateProfile(userId, parsed.data)\n\n  // 关键：写操作后做缓存失效\n  revalidatePath('/settings')\n}\n",[3253],{"type":27,"tag":41,"props":3254,"children":3255},{"__ignoreMap":7},[3256],{"type":33,"value":3251},{"type":27,"tag":35,"props":3258,"children":3259},{},[3260],{"type":33,"value":3261},"这个结构的好处：",{"type":27,"tag":345,"props":3263,"children":3264},{},[3265,3270,3275],{"type":27,"tag":270,"props":3266,"children":3267},{},[3268],{"type":33,"value":3269},"Action 层是“协议适配器”，服务层是“领域逻辑”",{"type":27,"tag":270,"props":3271,"children":3272},{},[3273],{"type":33,"value":3274},"输入校验与鉴权在入口处统一完成",{"type":27,"tag":270,"props":3276,"children":3277},{},[3278],{"type":33,"value":3279},"缓存失效在入口处统一声明",{"type":27,"tag":63,"props":3281,"children":3282},{},[],{"type":27,"tag":28,"props":3284,"children":3286},{"id":3285},"_5-安全边界你必须明确回答的-5-个问题",[3287],{"type":33,"value":3288},"5. 安全边界：你必须明确回答的 5 个问题",{"type":27,"tag":35,"props":3290,"children":3291},{},[3292],{"type":33,"value":3293},"Server Actions 容易让人产生错觉：“既然在 server 执行，那就是安全的”。",{"type":27,"tag":35,"props":3295,"children":3296},{},[3297,3299,3304],{"type":33,"value":3298},"更准确的说法是：",{"type":27,"tag":775,"props":3300,"children":3301},{},[3302],{"type":33,"value":3303},"Server Actions 让调用路径更短，但安全问题一个都不会消失",{"type":33,"value":781},{"type":27,"tag":914,"props":3306,"children":3308},{"id":3307},"_51-认证action-里必须做鉴权",[3309],{"type":33,"value":3310},"5.1 认证：Action 里必须做鉴权",{"type":27,"tag":35,"props":3312,"children":3313},{},[3314],{"type":33,"value":3315},"不要假设“只有页面能调用它”。",{"type":27,"tag":345,"props":3317,"children":3318},{},[3319,3324],{"type":27,"tag":270,"props":3320,"children":3321},{},[3322],{"type":33,"value":3323},"攻击者可以构造请求直接触发 action",{"type":27,"tag":270,"props":3325,"children":3326},{},[3327],{"type":33,"value":3328},"也可能通过 XSS / 依赖污染从客户端触发",{"type":27,"tag":35,"props":3330,"children":3331},{},[3332,3333],{"type":33,"value":1095},{"type":27,"tag":775,"props":3334,"children":3335},{},[3336],{"type":33,"value":3337},"每个会修改数据的 action，都要在服务端检查身份与权限。",{"type":27,"tag":914,"props":3339,"children":3341},{"id":3340},"_52-输入校验永远不要信任-formdata",[3342],{"type":33,"value":3343},"5.2 输入校验：永远不要信任 FormData",{"type":27,"tag":345,"props":3345,"children":3346},{},[3347,3352],{"type":27,"tag":270,"props":3348,"children":3349},{},[3350],{"type":33,"value":3351},"字段缺失、空字符串、超长、类型错",{"type":27,"tag":270,"props":3353,"children":3354},{},[3355],{"type":33,"value":3356},"业务约束（例如“昵称不得包含敏感词”）",{"type":27,"tag":35,"props":3358,"children":3359},{},[3360],{"type":33,"value":3361},"建议：用 schema 校验（zod）或你们统一的 validator。",{"type":27,"tag":914,"props":3363,"children":3365},{"id":3364},"_53-幂等与重放写操作要能承受重复执行",[3366],{"type":33,"value":3367},"5.3 幂等与重放：写操作要能承受重复执行",{"type":27,"tag":35,"props":3369,"children":3370},{},[3371],{"type":33,"value":3372},"浏览器/网络层可能导致重复提交。",{"type":27,"tag":35,"props":3374,"children":3375},{},[3376],{"type":33,"value":3377},"常见策略：",{"type":27,"tag":345,"props":3379,"children":3380},{},[3381,3392,3405],{"type":27,"tag":270,"props":3382,"children":3383},{},[3384,3386],{"type":33,"value":3385},"业务幂等键：",{"type":27,"tag":41,"props":3387,"children":3389},{"className":3388},[],[3390],{"type":33,"value":3391},"idempotencyKey",{"type":27,"tag":270,"props":3393,"children":3394},{},[3395,3397,3403],{"type":33,"value":3396},"数据层唯一约束：例如 ",{"type":27,"tag":41,"props":3398,"children":3400},{"className":3399},[],[3401],{"type":33,"value":3402},"(userId, itemId)",{"type":33,"value":3404}," 唯一",{"type":27,"tag":270,"props":3406,"children":3407},{},[3408],{"type":33,"value":3409},"事务：确保写入一致",{"type":27,"tag":914,"props":3411,"children":3413},{"id":3412},"_54-csrf优先走-form-action并启用-same-site-策略",[3414],{"type":33,"value":3415},"5.4 CSRF：优先走 form action，并启用 same-site 策略",{"type":27,"tag":35,"props":3417,"children":3418},{},[3419],{"type":33,"value":3420},"Server Actions 不等于“自动免疫 CSRF”。",{"type":27,"tag":345,"props":3422,"children":3423},{},[3424,3429],{"type":27,"tag":270,"props":3425,"children":3426},{},[3427],{"type":33,"value":3428},"如果你依赖 cookie 会话，仍要考虑跨站请求",{"type":27,"tag":270,"props":3430,"children":3431},{},[3432,3434,3440],{"type":33,"value":3433},"form action 的默认行为更符合浏览器标准，但你仍需要正确配置 cookie 的 ",{"type":27,"tag":41,"props":3435,"children":3437},{"className":3436},[],[3438],{"type":33,"value":3439},"SameSite",{"type":33,"value":3441}," 和 token",{"type":27,"tag":914,"props":3443,"children":3445},{"id":3444},"_55-错误回传不要把内部错误直接暴露给用户",[3446],{"type":33,"value":3447},"5.5 错误回传：不要把内部错误直接暴露给用户",{"type":27,"tag":35,"props":3449,"children":3450},{},[3451],{"type":33,"value":3452},"Action 抛出的错误最终会影响 UI。",{"type":27,"tag":35,"props":3454,"children":3455},{},[3456],{"type":33,"value":1232},{"type":27,"tag":345,"props":3458,"children":3459},{},[3460,3465],{"type":27,"tag":270,"props":3461,"children":3462},{},[3463],{"type":33,"value":3464},"对用户展示：可理解的、稳定的错误码/文案",{"type":27,"tag":270,"props":3466,"children":3467},{},[3468],{"type":33,"value":3469},"对服务端记录：完整 stack、请求上下文、userId、traceId",{"type":27,"tag":63,"props":3471,"children":3472},{},[],{"type":27,"tag":28,"props":3474,"children":3476},{"id":3475},"_6-缓存语义写操作之后页面为什么不更新",[3477],{"type":33,"value":3478},"6. 缓存语义：写操作之后，页面为什么不更新？",{"type":27,"tag":35,"props":3480,"children":3481},{},[3482],{"type":33,"value":3483},"在 App Router 模型里，“看起来像 SSR 的页面”实际上可能被缓存。",{"type":27,"tag":35,"props":3485,"children":3486},{},[3487],{"type":33,"value":3488},"你需要掌握 3 个概念：",{"type":27,"tag":345,"props":3490,"children":3491},{},[3492,3502,3512],{"type":27,"tag":270,"props":3493,"children":3494},{},[3495,3500],{"type":27,"tag":775,"props":3496,"children":3497},{},[3498],{"type":33,"value":3499},"请求缓存",{"type":33,"value":3501},"（fetch cache）",{"type":27,"tag":270,"props":3503,"children":3504},{},[3505,3510],{"type":27,"tag":775,"props":3506,"children":3507},{},[3508],{"type":33,"value":3509},"页面/路由段缓存",{"type":33,"value":3511},"（RSC payload cache）",{"type":27,"tag":270,"props":3513,"children":3514},{},[3515,3520],{"type":27,"tag":775,"props":3516,"children":3517},{},[3518],{"type":33,"value":3519},"失效机制",{"type":33,"value":3521},"（revalidatePath / revalidateTag）",{"type":27,"tag":914,"props":3523,"children":3525},{"id":3524},"_61-写操作后推荐怎么做",[3526],{"type":33,"value":3527},"6.1 写操作后，推荐怎么做？",{"type":27,"tag":345,"props":3529,"children":3530},{},[3531,3541],{"type":27,"tag":270,"props":3532,"children":3533},{},[3534,3536],{"type":33,"value":3535},"更新某个页面：",{"type":27,"tag":41,"props":3537,"children":3539},{"className":3538},[],[3540],{"type":33,"value":1348},{"type":27,"tag":270,"props":3542,"children":3543},{},[3544,3546],{"type":33,"value":3545},"更新多个数据源：给 fetch 打 tag，然后 ",{"type":27,"tag":41,"props":3547,"children":3549},{"className":3548},[],[3550],{"type":33,"value":3551},"revalidateTag('tag-name')",{"type":27,"tag":35,"props":3553,"children":3554},{},[3555],{"type":33,"value":3556},"建议的经验法则：",{"type":27,"tag":345,"props":3558,"children":3559},{},[3560,3571],{"type":27,"tag":270,"props":3561,"children":3562},{},[3563,3565],{"type":33,"value":3564},"页面级别更新不多：优先 ",{"type":27,"tag":41,"props":3566,"children":3568},{"className":3567},[],[3569],{"type":33,"value":3570},"revalidatePath",{"type":27,"tag":270,"props":3572,"children":3573},{},[3574,3576],{"type":33,"value":3575},"数据在多个页面复用：优先 ",{"type":27,"tag":41,"props":3577,"children":3579},{"className":3578},[],[3580],{"type":33,"value":758},{"type":27,"tag":914,"props":3582,"children":3584},{"id":3583},"_62-不要滥用-revalidatepath",[3585,3587],{"type":33,"value":3586},"6.2 不要滥用 ",{"type":27,"tag":41,"props":3588,"children":3590},{"className":3589},[],[3591],{"type":33,"value":1502},{"type":27,"tag":35,"props":3593,"children":3594},{},[3595],{"type":33,"value":3596},"这会让你的缓存命中率断崖式下降。",{"type":27,"tag":35,"props":3598,"children":3599},{},[3600],{"type":33,"value":3601},"更好的做法：",{"type":27,"tag":345,"props":3603,"children":3604},{},[3605,3610],{"type":27,"tag":270,"props":3606,"children":3607},{},[3608],{"type":33,"value":3609},"只失效受影响的 route segment",{"type":27,"tag":270,"props":3611,"children":3612},{},[3613],{"type":33,"value":3614},"用 tag 精准失效",{"type":27,"tag":63,"props":3616,"children":3617},{},[],{"type":27,"tag":28,"props":3619,"children":3621},{"id":3620},"_7-并发与用户体验让-action-看起来快而可靠",[3622],{"type":33,"value":3623},"7. 并发与用户体验：让 Action 看起来“快而可靠”",{"type":27,"tag":914,"props":3625,"children":3627},{"id":3626},"_71-usetransition-与-pending-状态",[3628,3630,3636],{"type":33,"value":3629},"7.1 ",{"type":27,"tag":41,"props":3631,"children":3633},{"className":3632},[],[3634],{"type":33,"value":3635},"useTransition",{"type":33,"value":3637}," 与 Pending 状态",{"type":27,"tag":35,"props":3639,"children":3640},{},[3641],{"type":33,"value":3642},"当 action 触发后，用户需要看到明确反馈。",{"type":27,"tag":345,"props":3644,"children":3645},{},[3646,3651,3656],{"type":27,"tag":270,"props":3647,"children":3648},{},[3649],{"type":33,"value":3650},"按钮 loading",{"type":27,"tag":270,"props":3652,"children":3653},{},[3654],{"type":33,"value":3655},"禁用重复提交",{"type":27,"tag":270,"props":3657,"children":3658},{},[3659],{"type":33,"value":3660},"成功/失败 toast",{"type":27,"tag":914,"props":3662,"children":3664},{"id":3663},"_72-乐观更新谨慎",[3665],{"type":33,"value":3666},"7.2 乐观更新（谨慎）",{"type":27,"tag":35,"props":3668,"children":3669},{},[3670],{"type":33,"value":3671},"乐观更新适合：",{"type":27,"tag":345,"props":3673,"children":3674},{},[3675,3680,3685],{"type":27,"tag":270,"props":3676,"children":3677},{},[3678],{"type":33,"value":3679},"可快速回滚",{"type":27,"tag":270,"props":3681,"children":3682},{},[3683],{"type":33,"value":3684},"失败概率低",{"type":27,"tag":270,"props":3686,"children":3687},{},[3688],{"type":33,"value":3689},"用户对即时反馈敏感（点赞/收藏）",{"type":27,"tag":35,"props":3691,"children":3692},{},[3693],{"type":33,"value":3694},"对“资金/权限/关键数据”写操作不建议乐观更新。",{"type":27,"tag":63,"props":3696,"children":3697},{},[],{"type":27,"tag":28,"props":3699,"children":3701},{"id":3700},"_8-什么时候不该用-server-actions",[3702],{"type":33,"value":3703},"8. 什么时候不该用 Server Actions？",{"type":27,"tag":345,"props":3705,"children":3706},{},[3707,3712,3717],{"type":27,"tag":270,"props":3708,"children":3709},{},[3710],{"type":33,"value":3711},"需要对外开放的公共 API（给第三方/移动端）",{"type":27,"tag":270,"props":3713,"children":3714},{},[3715],{"type":33,"value":3716},"需要长时间运行的任务（应改为队列/异步任务）",{"type":27,"tag":270,"props":3718,"children":3719},{},[3720],{"type":33,"value":3721},"需要复杂流控/网关策略（限流、WAF、跨服务认证）",{"type":27,"tag":35,"props":3723,"children":3724},{},[3725],{"type":33,"value":3726},"Server Actions 是“Web 应用内的写操作入口”，不是 API 网关替代品。",{"type":27,"tag":63,"props":3728,"children":3729},{},[],{"type":27,"tag":28,"props":3731,"children":3733},{"id":3732},"_9-生产级检查清单",[3734],{"type":33,"value":3735},"9. 生产级检查清单",{"type":27,"tag":35,"props":3737,"children":3738},{},[3739],{"type":33,"value":3740},"在把某个写操作迁移到 Server Actions 前，按这份清单过一遍：",{"type":27,"tag":345,"props":3742,"children":3744},{"className":3743},[1811],[3745,3754,3763,3772,3781,3790],{"type":27,"tag":270,"props":3746,"children":3748},{"className":3747},[1816],[3749,3752],{"type":27,"tag":1819,"props":3750,"children":3751},{"disabled":761,"type":1821},[],{"type":33,"value":3753}," action 是否做了鉴权与权限校验",{"type":27,"tag":270,"props":3755,"children":3757},{"className":3756},[1816],[3758,3761],{"type":27,"tag":1819,"props":3759,"children":3760},{"disabled":761,"type":1821},[],{"type":33,"value":3762}," 输入是否做了 schema 校验",{"type":27,"tag":270,"props":3764,"children":3766},{"className":3765},[1816],[3767,3770],{"type":27,"tag":1819,"props":3768,"children":3769},{"disabled":761,"type":1821},[],{"type":33,"value":3771}," 是否具备幂等策略（或数据层唯一约束）",{"type":27,"tag":270,"props":3773,"children":3775},{"className":3774},[1816],[3776,3779],{"type":27,"tag":1819,"props":3777,"children":3778},{"disabled":761,"type":1821},[],{"type":33,"value":3780}," 是否定义了稳定的错误码/文案",{"type":27,"tag":270,"props":3782,"children":3784},{"className":3783},[1816],[3785,3788],{"type":27,"tag":1819,"props":3786,"children":3787},{"disabled":761,"type":1821},[],{"type":33,"value":3789}," 写操作后是否做了精确的缓存失效（path/tag）",{"type":27,"tag":270,"props":3791,"children":3793},{"className":3792},[1816],[3794,3797],{"type":27,"tag":1819,"props":3795,"children":3796},{"disabled":761,"type":1821},[],{"type":33,"value":3798}," 是否有可观测性：日志、traceId、错误上报",{"type":27,"tag":63,"props":3800,"children":3801},{},[],{"type":27,"tag":28,"props":3803,"children":3805},{"id":3804},"_10-总结",[3806],{"type":33,"value":3807},"10. 总结",{"type":27,"tag":35,"props":3809,"children":3810},{},[3811],{"type":33,"value":3812},"Server Actions 的正确价值不是“少写 API”，而是：",{"type":27,"tag":345,"props":3814,"children":3815},{},[3816,3821,3826],{"type":27,"tag":270,"props":3817,"children":3818},{},[3819],{"type":33,"value":3820},"把写操作纳入 App Router/RSC 的统一模型",{"type":27,"tag":270,"props":3822,"children":3823},{},[3824],{"type":33,"value":3825},"让缓存失效与 UI 刷新更一致",{"type":27,"tag":270,"props":3827,"children":3828},{},[3829],{"type":33,"value":3830},"在正确工程结构下，显著减少样板代码与类型漂移",{"title":7,"searchDepth":732,"depth":732,"links":3832},[3833,3834,3835,3840,3844,3845,3852,3857,3862,3863,3864],{"id":2760,"depth":735,"text":712},{"id":2835,"depth":735,"text":2838},{"id":2935,"depth":735,"text":2938,"children":3836},[3837,3839],{"id":2941,"depth":732,"text":3838},"2.1 'use server' 不是运行时开关，而是编译期边界",{"id":3018,"depth":732,"text":3021},{"id":3076,"depth":735,"text":3079,"children":3841},[3842,3843],{"id":3082,"depth":732,"text":3085},{"id":3139,"depth":732,"text":3142},{"id":3180,"depth":735,"text":3183},{"id":3285,"depth":735,"text":3288,"children":3846},[3847,3848,3849,3850,3851],{"id":3307,"depth":732,"text":3310},{"id":3340,"depth":732,"text":3343},{"id":3364,"depth":732,"text":3367},{"id":3412,"depth":732,"text":3415},{"id":3444,"depth":732,"text":3447},{"id":3475,"depth":735,"text":3478,"children":3853},[3854,3855],{"id":3524,"depth":732,"text":3527},{"id":3583,"depth":732,"text":3856},"6.2 不要滥用 revalidatePath('/')",{"id":3620,"depth":735,"text":3623,"children":3858},[3859,3861],{"id":3626,"depth":732,"text":3860},"7.1 useTransition 与 Pending 状态",{"id":3663,"depth":732,"text":3666},{"id":3700,"depth":735,"text":3703},{"id":3732,"depth":735,"text":3735},{"id":3804,"depth":735,"text":3807},"content:topics:next:server-actions-complete-guide.md","topics/next/server-actions-complete-guide.md","topics/next/server-actions-complete-guide",{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"topic":5,"author":11,"tags":3869,"image":18,"imageQuery":19,"pexelsPhotoId":20,"pexelsUrl":21,"featured":6,"readingTime":22,"body":3870,"_type":745,"_id":746,"_source":747,"_file":748,"_stem":749,"_extension":750},[13,14,15,16,17],{"type":24,"children":3871,"toc":4436},[3872,3876,3892,3896,3899,3903,3907,3991,3995,3998,4002,4006,4014,4018,4026,4042,4045,4049,4053,4057,4072,4076,4080,4088,4092,4095,4099,4109,4117,4121,4136,4140,4143,4147,4151,4170,4174,4178,4193,4197,4212,4215,4219,4223,4307,4311,4314,4318,4322,4330,4334,4349,4353,4356,4360,4397,4400,4404,4408,4412],{"type":27,"tag":28,"props":3873,"children":3874},{"id":30},[3875],{"type":33,"value":8},{"type":27,"tag":35,"props":3877,"children":3878},{},[3879,3880,3885,3886,3891],{"type":33,"value":39},{"type":27,"tag":41,"props":3881,"children":3883},{"className":3882},[],[3884],{"type":33,"value":46},{"type":33,"value":48},{"type":27,"tag":41,"props":3887,"children":3889},{"className":3888},[],[3890],{"type":33,"value":54},{"type":33,"value":56},{"type":27,"tag":35,"props":3893,"children":3894},{},[3895],{"type":33,"value":61},{"type":27,"tag":63,"props":3897,"children":3898},{},[],{"type":27,"tag":28,"props":3900,"children":3901},{"id":68},[3902],{"type":33,"value":71},{"type":27,"tag":35,"props":3904,"children":3905},{},[3906],{"type":33,"value":76},{"type":27,"tag":78,"props":3908,"children":3909},{},[3910,3928],{"type":27,"tag":82,"props":3911,"children":3912},{},[3913],{"type":27,"tag":86,"props":3914,"children":3915},{},[3916,3920,3924],{"type":27,"tag":90,"props":3917,"children":3918},{},[3919],{"type":33,"value":94},{"type":27,"tag":90,"props":3921,"children":3922},{},[3923],{"type":33,"value":99},{"type":27,"tag":90,"props":3925,"children":3926},{},[3927],{"type":33,"value":104},{"type":27,"tag":106,"props":3929,"children":3930},{},[3931,3946,3961,3976],{"type":27,"tag":86,"props":3932,"children":3933},{},[3934,3938,3942],{"type":27,"tag":113,"props":3935,"children":3936},{},[3937],{"type":33,"value":117},{"type":27,"tag":113,"props":3939,"children":3940},{},[3941],{"type":33,"value":122},{"type":27,"tag":113,"props":3943,"children":3944},{},[3945],{"type":33,"value":127},{"type":27,"tag":86,"props":3947,"children":3948},{},[3949,3953,3957],{"type":27,"tag":113,"props":3950,"children":3951},{},[3952],{"type":33,"value":135},{"type":27,"tag":113,"props":3954,"children":3955},{},[3956],{"type":33,"value":140},{"type":27,"tag":113,"props":3958,"children":3959},{},[3960],{"type":33,"value":145},{"type":27,"tag":86,"props":3962,"children":3963},{},[3964,3968,3972],{"type":27,"tag":113,"props":3965,"children":3966},{},[3967],{"type":33,"value":153},{"type":27,"tag":113,"props":3969,"children":3970},{},[3971],{"type":33,"value":158},{"type":27,"tag":113,"props":3973,"children":3974},{},[3975],{"type":33,"value":163},{"type":27,"tag":86,"props":3977,"children":3978},{},[3979,3983,3987],{"type":27,"tag":113,"props":3980,"children":3981},{},[3982],{"type":33,"value":171},{"type":27,"tag":113,"props":3984,"children":3985},{},[3986],{"type":33,"value":140},{"type":27,"tag":113,"props":3988,"children":3989},{},[3990],{"type":33,"value":180},{"type":27,"tag":35,"props":3992,"children":3993},{},[3994],{"type":33,"value":185},{"type":27,"tag":63,"props":3996,"children":3997},{},[],{"type":27,"tag":28,"props":3999,"children":4000},{"id":191},[4001],{"type":33,"value":194},{"type":27,"tag":35,"props":4003,"children":4004},{},[4005],{"type":33,"value":199},{"type":27,"tag":201,"props":4007,"children":4009},{"className":4008,"code":205,"language":206,"meta":7},[204],[4010],{"type":27,"tag":41,"props":4011,"children":4012},{"__ignoreMap":7},[4013],{"type":33,"value":205},{"type":27,"tag":35,"props":4015,"children":4016},{},[4017],{"type":33,"value":216},{"type":27,"tag":201,"props":4019,"children":4021},{"className":4020,"code":220,"language":206,"meta":7},[204],[4022],{"type":27,"tag":41,"props":4023,"children":4024},{"__ignoreMap":7},[4025],{"type":33,"value":220},{"type":27,"tag":35,"props":4027,"children":4028},{},[4029,4030,4035,4036,4041],{"type":33,"value":230},{"type":27,"tag":41,"props":4031,"children":4033},{"className":4032},[],[4034],{"type":33,"value":236},{"type":33,"value":238},{"type":27,"tag":41,"props":4037,"children":4039},{"className":4038},[],[4040],{"type":33,"value":54},{"type":33,"value":245},{"type":27,"tag":63,"props":4043,"children":4044},{},[],{"type":27,"tag":28,"props":4046,"children":4047},{"id":251},[4048],{"type":33,"value":254},{"type":27,"tag":35,"props":4050,"children":4051},{},[4052],{"type":33,"value":259},{"type":27,"tag":35,"props":4054,"children":4055},{},[4056],{"type":33,"value":264},{"type":27,"tag":266,"props":4058,"children":4059},{},[4060,4064,4068],{"type":27,"tag":270,"props":4061,"children":4062},{},[4063],{"type":33,"value":274},{"type":27,"tag":270,"props":4065,"children":4066},{},[4067],{"type":33,"value":279},{"type":27,"tag":270,"props":4069,"children":4070},{},[4071],{"type":33,"value":284},{"type":27,"tag":35,"props":4073,"children":4074},{},[4075],{"type":33,"value":289},{"type":27,"tag":35,"props":4077,"children":4078},{},[4079],{"type":33,"value":294},{"type":27,"tag":201,"props":4081,"children":4083},{"className":4082,"code":298,"language":206,"meta":7},[204],[4084],{"type":27,"tag":41,"props":4085,"children":4086},{"__ignoreMap":7},[4087],{"type":33,"value":298},{"type":27,"tag":35,"props":4089,"children":4090},{},[4091],{"type":33,"value":308},{"type":27,"tag":63,"props":4093,"children":4094},{},[],{"type":27,"tag":28,"props":4096,"children":4097},{"id":314},[4098],{"type":33,"value":317},{"type":27,"tag":35,"props":4100,"children":4101},{},[4102,4103,4108],{"type":33,"value":322},{"type":27,"tag":41,"props":4104,"children":4106},{"className":4105},[],[4107],{"type":33,"value":54},{"type":33,"value":329},{"type":27,"tag":201,"props":4110,"children":4112},{"className":4111,"code":333,"language":206,"meta":7},[204],[4113],{"type":27,"tag":41,"props":4114,"children":4115},{"__ignoreMap":7},[4116],{"type":33,"value":333},{"type":27,"tag":35,"props":4118,"children":4119},{},[4120],{"type":33,"value":343},{"type":27,"tag":345,"props":4122,"children":4123},{},[4124,4128,4132],{"type":27,"tag":270,"props":4125,"children":4126},{},[4127],{"type":33,"value":352},{"type":27,"tag":270,"props":4129,"children":4130},{},[4131],{"type":33,"value":357},{"type":27,"tag":270,"props":4133,"children":4134},{},[4135],{"type":33,"value":362},{"type":27,"tag":35,"props":4137,"children":4138},{},[4139],{"type":33,"value":367},{"type":27,"tag":63,"props":4141,"children":4142},{},[],{"type":27,"tag":28,"props":4144,"children":4145},{"id":373},[4146],{"type":33,"value":376},{"type":27,"tag":35,"props":4148,"children":4149},{},[4150],{"type":33,"value":381},{"type":27,"tag":266,"props":4152,"children":4153},{},[4154,4158,4162,4166],{"type":27,"tag":270,"props":4155,"children":4156},{},[4157],{"type":33,"value":389},{"type":27,"tag":270,"props":4159,"children":4160},{},[4161],{"type":33,"value":394},{"type":27,"tag":270,"props":4163,"children":4164},{},[4165],{"type":33,"value":399},{"type":27,"tag":270,"props":4167,"children":4168},{},[4169],{"type":33,"value":404},{"type":27,"tag":35,"props":4171,"children":4172},{},[4173],{"type":33,"value":409},{"type":27,"tag":35,"props":4175,"children":4176},{},[4177],{"type":33,"value":414},{"type":27,"tag":345,"props":4179,"children":4180},{},[4181,4185,4189],{"type":27,"tag":270,"props":4182,"children":4183},{},[4184],{"type":33,"value":422},{"type":27,"tag":270,"props":4186,"children":4187},{},[4188],{"type":33,"value":427},{"type":27,"tag":270,"props":4190,"children":4191},{},[4192],{"type":33,"value":432},{"type":27,"tag":35,"props":4194,"children":4195},{},[4196],{"type":33,"value":437},{"type":27,"tag":345,"props":4198,"children":4199},{},[4200,4204,4208],{"type":27,"tag":270,"props":4201,"children":4202},{},[4203],{"type":33,"value":445},{"type":27,"tag":270,"props":4205,"children":4206},{},[4207],{"type":33,"value":450},{"type":27,"tag":270,"props":4209,"children":4210},{},[4211],{"type":33,"value":455},{"type":27,"tag":63,"props":4213,"children":4214},{},[],{"type":27,"tag":28,"props":4216,"children":4217},{"id":461},[4218],{"type":33,"value":464},{"type":27,"tag":35,"props":4220,"children":4221},{},[4222],{"type":33,"value":469},{"type":27,"tag":78,"props":4224,"children":4225},{},[4226,4244],{"type":27,"tag":82,"props":4227,"children":4228},{},[4229],{"type":27,"tag":86,"props":4230,"children":4231},{},[4232,4236,4240],{"type":27,"tag":90,"props":4233,"children":4234},{},[4235],{"type":33,"value":483},{"type":27,"tag":90,"props":4237,"children":4238},{},[4239],{"type":33,"value":488},{"type":27,"tag":90,"props":4241,"children":4242},{},[4243],{"type":33,"value":493},{"type":27,"tag":106,"props":4245,"children":4246},{},[4247,4262,4277,4292],{"type":27,"tag":86,"props":4248,"children":4249},{},[4250,4254,4258],{"type":27,"tag":113,"props":4251,"children":4252},{},[4253],{"type":33,"value":504},{"type":27,"tag":113,"props":4255,"children":4256},{},[4257],{"type":33,"value":509},{"type":27,"tag":113,"props":4259,"children":4260},{},[4261],{"type":33,"value":514},{"type":27,"tag":86,"props":4263,"children":4264},{},[4265,4269,4273],{"type":27,"tag":113,"props":4266,"children":4267},{},[4268],{"type":33,"value":522},{"type":27,"tag":113,"props":4270,"children":4271},{},[4272],{"type":33,"value":527},{"type":27,"tag":113,"props":4274,"children":4275},{},[4276],{"type":33,"value":532},{"type":27,"tag":86,"props":4278,"children":4279},{},[4280,4284,4288],{"type":27,"tag":113,"props":4281,"children":4282},{},[4283],{"type":33,"value":540},{"type":27,"tag":113,"props":4285,"children":4286},{},[4287],{"type":33,"value":545},{"type":27,"tag":113,"props":4289,"children":4290},{},[4291],{"type":33,"value":550},{"type":27,"tag":86,"props":4293,"children":4294},{},[4295,4299,4303],{"type":27,"tag":113,"props":4296,"children":4297},{},[4298],{"type":33,"value":558},{"type":27,"tag":113,"props":4300,"children":4301},{},[4302],{"type":33,"value":563},{"type":27,"tag":113,"props":4304,"children":4305},{},[4306],{"type":33,"value":568},{"type":27,"tag":35,"props":4308,"children":4309},{},[4310],{"type":33,"value":573},{"type":27,"tag":63,"props":4312,"children":4313},{},[],{"type":27,"tag":28,"props":4315,"children":4316},{"id":579},[4317],{"type":33,"value":582},{"type":27,"tag":35,"props":4319,"children":4320},{},[4321],{"type":33,"value":587},{"type":27,"tag":201,"props":4323,"children":4325},{"className":4324,"code":592,"language":593,"meta":7},[591],[4326],{"type":27,"tag":41,"props":4327,"children":4328},{"__ignoreMap":7},[4329],{"type":33,"value":592},{"type":27,"tag":35,"props":4331,"children":4332},{},[4333],{"type":33,"value":603},{"type":27,"tag":345,"props":4335,"children":4336},{},[4337,4341,4345],{"type":27,"tag":270,"props":4338,"children":4339},{},[4340],{"type":33,"value":611},{"type":27,"tag":270,"props":4342,"children":4343},{},[4344],{"type":33,"value":616},{"type":27,"tag":270,"props":4346,"children":4347},{},[4348],{"type":33,"value":621},{"type":27,"tag":35,"props":4350,"children":4351},{},[4352],{"type":33,"value":626},{"type":27,"tag":63,"props":4354,"children":4355},{},[],{"type":27,"tag":28,"props":4357,"children":4358},{"id":632},[4359],{"type":33,"value":635},{"type":27,"tag":345,"props":4361,"children":4362},{},[4363,4373,4377,4381,4385,4389,4393],{"type":27,"tag":270,"props":4364,"children":4365},{},[4366,4367,4372],{"type":33,"value":643},{"type":27,"tag":41,"props":4368,"children":4370},{"className":4369},[],[4371],{"type":33,"value":54},{"type":33,"value":650},{"type":27,"tag":270,"props":4374,"children":4375},{},[4376],{"type":33,"value":655},{"type":27,"tag":270,"props":4378,"children":4379},{},[4380],{"type":33,"value":660},{"type":27,"tag":270,"props":4382,"children":4383},{},[4384],{"type":33,"value":665},{"type":27,"tag":270,"props":4386,"children":4387},{},[4388],{"type":33,"value":670},{"type":27,"tag":270,"props":4390,"children":4391},{},[4392],{"type":33,"value":675},{"type":27,"tag":270,"props":4394,"children":4395},{},[4396],{"type":33,"value":680},{"type":27,"tag":63,"props":4398,"children":4399},{},[],{"type":27,"tag":28,"props":4401,"children":4402},{"id":686},[4403],{"type":33,"value":689},{"type":27,"tag":35,"props":4405,"children":4406},{},[4407],{"type":33,"value":694},{"type":27,"tag":35,"props":4409,"children":4410},{},[4411],{"type":33,"value":699},{"type":27,"tag":345,"props":4413,"children":4414},{},[4415,4422,4429],{"type":27,"tag":270,"props":4416,"children":4417},{},[4418],{"type":27,"tag":707,"props":4419,"children":4420},{"href":709},[4421],{"type":33,"value":712},{"type":27,"tag":270,"props":4423,"children":4424},{},[4425],{"type":27,"tag":707,"props":4426,"children":4427},{"href":718},[4428],{"type":33,"value":721},{"type":27,"tag":270,"props":4430,"children":4431},{},[4432],{"type":27,"tag":707,"props":4433,"children":4434},{"href":727},[4435],{"type":33,"value":730},{"title":7,"searchDepth":732,"depth":732,"links":4437},[4438,4439,4440,4441,4442,4443,4444,4445,4446,4447],{"id":30,"depth":735,"text":8},{"id":68,"depth":735,"text":71},{"id":191,"depth":735,"text":194},{"id":251,"depth":735,"text":254},{"id":314,"depth":735,"text":317},{"id":373,"depth":735,"text":376},{"id":461,"depth":735,"text":464},{"id":579,"depth":735,"text":582},{"id":632,"depth":735,"text":635},{"id":686,"depth":735,"text":689},1775659686503]