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