[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f9Ud1Tpcw3LNMYYK4j-Bzv8fhcYvS7XwWiOgiGfHns9Y":3},{"meta":4,"toc":18,"html":35,"hasMore":15,"views":9,"prev":9,"next":36,"seriesList":9},{"slug":5,"title":6,"description":7,"date":8,"updated":9,"tags":10,"series":9,"seriesOrder":14,"cover":9,"price":14,"priceUsd":9,"paid":15,"draft":15,"words":16,"minutes":17},"nuxt3-paid-blog-architecture","用 Nuxt 3 搭建一个按篇付费的博客","从渲染策略、内容管线到付费墙安全模型，完整拆解本站的架构设计思路。","2026-08-02",null,[11,12,13],"Nuxt","架构","本站故事",0,false,577,2,[19,22,25,28,30,32],{"id":20,"text":21,"depth":17},"先想清楚付费内容放在哪里","先想清楚：付费内容放在哪里",{"id":23,"text":24,"depth":17},"渲染策略ssr--客户端解锁","渲染策略：SSR + 客户端解锁",{"id":26,"text":27,"depth":17},"内容管线markdown-是唯一事实源","内容管线：markdown 是唯一事实源",{"id":29,"text":29,"depth":17},"数学公式长什么样",{"id":31,"text":31,"depth":17},"小结",{"id":33,"text":34,"depth":17},"footnote-label","Footnotes","\u003Cp>很多人问这个站是怎么搭起来的。这篇文章把整体架构摊开讲清楚：\u003Cstrong>渲染策略、内容管线、付费墙安全模型\u003C\u002Fstrong>三个核心问题。\u003C\u002Fp>\n\u003Ch2 id=\"先想清楚付费内容放在哪里\">\u003Ca href=\"#先想清楚付费内容放在哪里\">先想清楚：付费内容放在哪里\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>按篇付费的博客，最容易踩的坑是把全文塞进前端 payload 再用 CSS 遮罩。右键查看源码就能白嫖，这不行。所以第一条铁律：\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>付费内容绝不出现在公开的 HTTP 响应里，包括 SSR 的 HTML、水合 payload、以及任何内部 API。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>本站的解法是「\u003Cstrong>构建期物理隔离\u003C\u002Fstrong>」：源文件 \u003Ccode>articles\u002F*.md\u003C\u002Fcode> 同时生成两份产物——\u003C\u002Fp>\n\u003Cpre class=\"shiki vesper\" style=\"background-color:#101010;color:#FFF\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan>server\u002Fassets\u002Fcontent\u002F\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>├── manifest.json          # 公开索引\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>├── previews\u002F&#x3C;slug>.json   # 预览段 HTML（可被爬虫抓取，SEO 友好）\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>└── full\u002F&#x3C;slug>.json       # 完整 HTML（仅 entitlement API 读取）\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Nitro 把 \u003Ccode>server\u002Fassets\u003C\u002Fcode> 挂载为服务端私有存储，公开 API 只读 \u003Ccode>previews\u002F\u003C\u002Fcode>，全文只通过一条校验购买状态的接口下发。物理上不可达，而不是逻辑上隐藏。\u003C\u002Fp>\n\u003Ch2 id=\"渲染策略ssr--客户端解锁\">\u003Ca href=\"#渲染策略ssr--客户端解锁\">渲染策略：SSR + 客户端解锁\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>页面本体走 SSR 并配合 \u003Ccode>swr\u003C\u002Fcode> 缓存，因为\u003Cstrong>公开部分与用户无关\u003C\u002Fstrong>；购买状态则在水合后由客户端请求 \u003Ccode>\u002Fapi\u002Farticles\u002F:slug\u002Ffull\u003C\u002Fcode> 拉取。这样同一篇文章的页面可以复用缓存，付费校验只发生在数据接口上。\u003C\u002Fp>\n\u003Cp>用一张图描述整条链路：\u003C\u002Fp>\n\u003Cdiv class=\"mermaid-block\" data-code=\"flowchart%20LR%0A%20%20%20%20A%5B%E8%AF%BB%E8%80%85%E8%AF%B7%E6%B1%82%E6%96%87%E7%AB%A0%5D%20--%3E%20B%7BSSR%20%E8%BF%94%E5%9B%9E%E9%A2%84%E8%A7%88%7D%0A%20%20%20%20B%20--%3E%20C%5B%E6%9C%AA%E7%99%BB%E5%BD%95%3F%20%E6%98%BE%E7%A4%BA%E7%99%BB%E5%BD%95%E5%BC%95%E5%AF%BC%5D%0A%20%20%20%20B%20--%3E%20D%5B%E5%B7%B2%E7%99%BB%E5%BD%95%E6%9C%AA%E8%B4%AD%E4%B9%B0%3F%20%E6%98%BE%E7%A4%BA%E4%BB%98%E8%B4%B9%E5%A2%99%5D%0A%20%20%20%20B%20--%3E%20E%5B%E5%B7%B2%E8%B4%AD%E4%B9%B0%3F%20%E8%AF%B7%E6%B1%82%20full%20API%5D%0A%20%20%20%20E%20--%3E%20F%5B%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%A0%A1%E9%AA%8C%20purchases%20%E8%A1%A8%5D%0A%20%20%20%20F%20--%3E%7C%E9%80%9A%E8%BF%87%7C%20G%5B%E8%BF%94%E5%9B%9E%E5%AE%8C%E6%95%B4%20HTML%5D%0A%20%20%20%20F%20--%3E%7C%E6%8B%92%E7%BB%9D%7C%20H%5B402%20Payment%20Required%5D\">\u003C\u002Fdiv>\n\u003Ch2 id=\"内容管线markdown-是唯一事实源\">\u003Ca href=\"#内容管线markdown-是唯一事实源\">内容管线：markdown 是唯一事实源\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>写作工作流保持极简——本地写 markdown、push 到 Git 仓库，没有任何在线后台。构建脚本用 unified 生态处理渲染：\u003C\u002Fp>\n\u003Cpre class=\"shiki vesper\" style=\"background-color:#101010;color:#FFF\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#A0A0A0\">const\u003C\u002Fspan>\u003Cspan style=\"color:#FFF\"> processor \u003C\u002Fspan>\u003Cspan style=\"color:#A0A0A0\">=\u003C\u002Fspan>\u003Cspan style=\"color:#FFC799\"> unified\u003C\u002Fspan>\u003Cspan style=\"color:#FFF\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFF\">  .\u003C\u002Fspan>\u003Cspan style=\"color:#FFC799\">use\u003C\u002Fspan>\u003Cspan style=\"color:#FFF\">(remarkParse)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFF\">  .\u003C\u002Fspan>\u003Cspan style=\"color:#FFC799\">use\u003C\u002Fspan>\u003Cspan style=\"color:#FFF\">(remarkGfm)        \u003C\u002Fspan>\u003Cspan style=\"color:#8B8B8B94\">\u002F\u002F 表格 \u002F 脚注 \u002F 任务列表\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFF\">  .\u003C\u002Fspan>\u003Cspan style=\"color:#FFC799\">use\u003C\u002Fspan>\u003Cspan style=\"color:#FFF\">(remarkMath)       \u003C\u002Fspan>\u003Cspan style=\"color:#8B8B8B94\">\u002F\u002F 数学公式入口\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFF\">  .\u003C\u002Fspan>\u003Cspan style=\"color:#FFC799\">use\u003C\u002Fspan>\u003Cspan style=\"color:#FFF\">(remarkRehype, { allowDangerousHtml: \u003C\u002Fspan>\u003Cspan style=\"color:#FFC799\">true\u003C\u002Fspan>\u003Cspan style=\"color:#FFF\"> })\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFF\">  .\u003C\u002Fspan>\u003Cspan style=\"color:#FFC799\">use\u003C\u002Fspan>\u003Cspan style=\"color:#FFF\">(rehypeKatex)      \u003C\u002Fspan>\u003Cspan style=\"color:#8B8B8B94\">\u002F\u002F 渲染 KaTeX\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFF\">  .\u003C\u002Fspan>\u003Cspan style=\"color:#FFC799\">use\u003C\u002Fspan>\u003Cspan style=\"color:#FFF\">(rehypeSlug)       \u003C\u002Fspan>\u003Cspan style=\"color:#8B8B8B94\">\u002F\u002F 标题锚点，供目录使用\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>代码高亮用的是 Shiki 的 \u003Ccode>vesper\u003C\u002Fcode> 主题，与整站暗色美学一致；Mermaid 图表在构建期仅留下占位符，浏览器端再实例化渲染，避免把整个图表引擎塞进首屏包。\u003C\u002Fp>\n\u003Ch2 id=\"数学公式长什么样\">\u003Ca href=\"#数学公式长什么样\">数学公式长什么样\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>讨论缓存命中率时随手推导一下 Little's Law\u003Csup>\u003Ca href=\"#user-content-fn-1\" id=\"user-content-fnref-1\" data-footnote-ref aria-describedby=\"footnote-label\">1\u003C\u002Fa>\u003C\u002Fsup>：\u003C\u002Fp>\n\u003Cp>\u003Cspan class=\"katex\">\u003Cspan class=\"katex-mathml\">\u003Cmath xmlns=\"http:\u002F\u002Fwww.w3.org\u002F1998\u002FMath\u002FMathML\">\u003Csemantics>\u003Cmrow>\u003Cmi>L\u003C\u002Fmi>\u003Cmo>=\u003C\u002Fmo>\u003Cmi>λ\u003C\u002Fmi>\u003Cmi>W\u003C\u002Fmi>\u003C\u002Fmrow>\u003Cannotation encoding=\"application\u002Fx-tex\">L = \\lambda W\u003C\u002Fannotation>\u003C\u002Fsemantics>\u003C\u002Fmath>\u003C\u002Fspan>\u003Cspan class=\"katex-html\" aria-hidden=\"true\">\u003Cspan class=\"base\">\u003Cspan class=\"strut\" style=\"height:0.6833em;\">\u003C\u002Fspan>\u003Cspan class=\"mord mathnormal\">L\u003C\u002Fspan>\u003Cspan class=\"mspace\" style=\"margin-right:0.2778em;\">\u003C\u002Fspan>\u003Cspan class=\"mrel\">=\u003C\u002Fspan>\u003Cspan class=\"mspace\" style=\"margin-right:0.2778em;\">\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"base\">\u003Cspan class=\"strut\" style=\"height:0.6944em;\">\u003C\u002Fspan>\u003Cspan class=\"mord mathnormal\" style=\"margin-right:0.1389em;\">λW\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>其中 \u003Cspan class=\"katex\">\u003Cspan class=\"katex-mathml\">\u003Cmath xmlns=\"http:\u002F\u002Fwww.w3.org\u002F1998\u002FMath\u002FMathML\">\u003Csemantics>\u003Cmrow>\u003Cmi>L\u003C\u002Fmi>\u003C\u002Fmrow>\u003Cannotation encoding=\"application\u002Fx-tex\">L\u003C\u002Fannotation>\u003C\u002Fsemantics>\u003C\u002Fmath>\u003C\u002Fspan>\u003Cspan class=\"katex-html\" aria-hidden=\"true\">\u003Cspan class=\"base\">\u003Cspan class=\"strut\" style=\"height:0.6833em;\">\u003C\u002Fspan>\u003Cspan class=\"mord mathnormal\">L\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan> 是系统中平均请求数，\u003Cspan class=\"katex\">\u003Cspan class=\"katex-mathml\">\u003Cmath xmlns=\"http:\u002F\u002Fwww.w3.org\u002F1998\u002FMath\u002FMathML\">\u003Csemantics>\u003Cmrow>\u003Cmi>λ\u003C\u002Fmi>\u003C\u002Fmrow>\u003Cannotation encoding=\"application\u002Fx-tex\">\\lambda\u003C\u002Fannotation>\u003C\u002Fsemantics>\u003C\u002Fmath>\u003C\u002Fspan>\u003Cspan class=\"katex-html\" aria-hidden=\"true\">\u003Cspan class=\"base\">\u003Cspan class=\"strut\" style=\"height:0.6944em;\">\u003C\u002Fspan>\u003Cspan class=\"mord mathnormal\">λ\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan> 是到达率，\u003Cspan class=\"katex\">\u003Cspan class=\"katex-mathml\">\u003Cmath xmlns=\"http:\u002F\u002Fwww.w3.org\u002F1998\u002FMath\u002FMathML\">\u003Csemantics>\u003Cmrow>\u003Cmi>W\u003C\u002Fmi>\u003C\u002Fmrow>\u003Cannotation encoding=\"application\u002Fx-tex\">W\u003C\u002Fannotation>\u003C\u002Fsemantics>\u003C\u002Fmath>\u003C\u002Fspan>\u003Cspan class=\"katex-html\" aria-hidden=\"true\">\u003Cspan class=\"base\">\u003Cspan class=\"strut\" style=\"height:0.6833em;\">\u003C\u002Fspan>\u003Cspan class=\"mord mathnormal\" style=\"margin-right:0.1389em;\">W\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan> 是平均停留时间。它对容量规划的指导意义在于：\u003Cstrong>并发数 = 吞吐 × 延迟\u003C\u002Fstrong>，三个量知二求一。\u003C\u002Fp>\n\u003Ch2 id=\"小结\">\u003Ca href=\"#小结\">小结\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>付费墙的安全靠「构建期隔离 + 服务端校验」，不靠前端遮罩\u003C\u002Fli>\n\u003Cli>渲染走 SSR，付费解锁走客户端接口，缓存互不干扰\u003C\u002Fli>\n\u003Cli>内容管线纯 Node 脚本，写作就是写 markdown\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>这套架构的数据库层（订单、购买凭证、RLS 策略）在后续的付费专栏里展开。\u003C\u002Fp>\n\u003Csection data-footnotes class=\"footnotes\">\u003Ch2 class=\"sr-only\" id=\"footnote-label\">\u003Ca href=\"#footnote-label\">Footnotes\u003C\u002Fa>\u003C\u002Fh2>\n\u003Col>\n\u003Cli id=\"user-content-fn-1\">\n\u003Cp>Little, J. D. C. (1961). \"A Proof for the Queuing Formula\". \u003Ca href=\"#user-content-fnref-1\" data-footnote-backref=\"\" aria-label=\"Back to reference 1\" class=\"data-footnote-backref\">↩\u003C\u002Fa>\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Fol>\n\u003C\u002Fsection>",{"slug":37,"title":38,"description":39,"date":40,"updated":9,"tags":41,"series":9,"seriesOrder":14,"cover":9,"price":45,"priceUsd":46,"paid":47,"draft":15,"words":48,"minutes":17},"vue-reactivity-deep-dive","Vue 响应式系统源码走读：从 effect 到调度器","逐行拆解 Vue 3 reactivity 的依赖收集与派发更新机制，理解 weakmap 三层结构与异步调度批处理。","2026-08-08",[42,43,44],"Vue","源码","JavaScript",9.9,1.99,true,597]