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