快捷菜单
常用功能一站直达
更多功能请点顶栏「快捷菜单」
来源@cusor auto(咸鱼购买)记录于2026.7.15。
来自@w3c提出。
1ssr是不刷缓存的
2从这就能看出来,含金量不高
3ssr刷啥缓存,又不是静态
4pages和函数里,就没刷缓存这个东西
5[破涕为笑]还没看里面内容 呢哈哈
6ssr本来就是实时渲染,刷啥缓存 [捂脸]
7还需要看里面吗
8都不是走cdn那条线
9只有cdn静态才要刷缓存
10hhhh you dao li
11反正 能修好 bugde ai 就是yyds
12这个方案,不行,退回去重写结论先行:可以做出「有后台、写完即见」的博客。
推荐路径:CNB 管代码与流水线 + Astro SSR(跑在 EdgeOne Pages / 边缘函数)+ KV 存索引与元数据 + Blob/对象存储存正文与媒体 + 轻量管理后台。
核心口径(必读):
文档日期:2026-07-15(同日纠正:去掉 SSR 主路径上的「刷缓存」误述)
适用对象:已有 Hugo Teek / EdgeOne / CNB 经验,希望升级「写完即见」体验的个人/小团队博客。
| 路线 | 内容怎么更新 | 要不要「刷缓存」 |
|---|---|---|
| SSG / 纯静态站(如传统 Hugo 产物丢 CDN) | 改内容 → 重新构建 → 覆盖静态文件;若 CDN 还缓存着旧 HTML,才要 刷新 URL / 刷目录 | 要(针对静态 HTML) |
| 纯 SSR(本方案主路径) | 后台写入 KV/Blob → 访客下次请求时 SSR 重新读存储并渲染 | 不要(动态响应本来就不是那份静态缓存) |
SSR + 人为给 HTML 加了 CDN/s-maxage | 等于把动态页又变成「短时静态」 | 才会引入失效问题;本方案默认不做,个人博客纯 SSR 通常够用 |
一句话:SSR 刷啥缓存?又不静态。实时来自存储,不来自 purge。
下文凡涉及发布流程、API、前台读模型,一律按 「写存储 → SSR 读存储」 描述。
| 能力 | 传统 Hugo SSG | 本方案目标 |
|---|---|---|
| 发文方式 | 改仓库 → CI → 全量构建 → 部署静态 | 后台提交 → 写入 KV/Blob → 下次 SSR 请求即新内容 |
| 后台 | 可选(Git 编辑) | Web 后台:登录、写稿、上传、预览、发布 |
| 实时性 | 受 CI 限制(分钟级) | 写库成功即可;访客刷新页面由 SSR 现读现渲染 |
| 流量路径 | 静态文件走 CDN | 请求进 Pages/函数做 SSR,内容源是 KV/Blob |
| 源码托管 | CNB / GitHub | 继续用 CNB(主题、后台、函数代码;不管日常发文) |
「实时」两档:
/api/updates 等;与「刷 CDN」无关。 1┌──────────────┐ Git Push / PR ┌─────────────────┐
2│ 作者 / 编辑 │ ─────────────────────► │ CNB 仓库 │
3│ (浏览器后台) │ │ Astro 主题+后台 │
4└──────┬───────┘ │ CI(仅改代码时) │
5 │ HTTPS API └────────┬────────┘
6 │ 写文章 / 登录 │ 部署主题与函数
7 ▼ ▼
8┌──────────────────────────────────────────────────────────────┐
9│ EdgeOne:Pages SSR + 边缘函数 │
10│ │
11│ 访客 GET /posts/xxx │
12│ │ │
13│ ▼ │
14│ ┌─────────────┐ 读最新 ┌────────────────────────┐ │
15│ │ Astro SSR │◄───────────────►│ KV:索引 / meta / 配置 │ │
16│ │ 当场渲染 HTML│ └────────────────────────┘ │
17│ └─────────────┘ 读正文 ┌────────────────────────┐ │
18│ ▲ │ Blob / COS:Markdown 等 │ │
19│ │ ◄───────────┤ 媒体文件 │ │
20│ ┌─────────────┐ 写入口 └────────────────────────┘ │
21│ │ 边缘函数 API │──────────────────────────────────────────►│
22│ │ 鉴权 + CRUD │ 只负责读写存储,不负责「刷静态 CDN」 │
23│ └─────────────┘ │
24└──────────────────────────────────────────────────────────────┘
25 │
26 ▼ 浏览器(得到的是本次请求渲染结果,不是 CDN 里某份旧静态页)| 组件 | 职责 |
|---|---|
| CNB 仓库 | 主题、后台前端、边缘函数源码、CI;日常发文不进 Git |
| Astro SSR | 每个(或每个进函数的)请求从 KV/Blob 取数并渲染 |
| EO 边缘函数 | 后台 API:登录、发布、上传、删改;写 KV/Blob |
| EO Pages KV | 文章索引、post:meta:{slug}、站点配置、Session |
| EO Blob / COS | 正文、图片、附件 |
| 管理后台 | /admin 或独立站;只调写接口 |
刻意不做的事(主路径): 发布成功后再调「刷新全站 HTML 缓存」。那是静态站逻辑。
/ 列表设为 服务端渲染,prerender = false。posts:index / post:meta / Blob → Markdown 转 HTML → 返回。| 资源 | 怎么交付 | 变了怎么办 |
|---|---|---|
| 文章 HTML | SSR 动态生成 | 改 KV/Blob 即可 |
app.*.js / 主题 CSS | 常随部署带 hash,可走 CDN | 跟发文无关;改主题才重新部署 |
| 用户上传的封面图 | Blob/COS URL | 新 URL 或覆盖对象;HTML 下次 SSR 引用新地址 |
不要把「图片 CDN」「主题静态资源」和「文章页 SSR」混成同一套「刷缓存」叙事。
1site:config → 站点配置 JSON
2posts:index → 已发布摘要列表(倒序)
3posts:drafts → 草稿 slug 列表
4post:meta:{slug} → title/date/tags/cover/status/blobKey/version
5auth:user:{id} → 密码哈希、角色
6session:{token} → 可选;也可用纯 JWT
7site:lastPublishedAt → 可选,给前台轮询「有没有新文」1content/posts/{slug}/latest.md
2content/posts/{slug}/v{n}.md
3media/{yyyy}/{mm}/{uuid}.{ext}Blob.put(latest.md)KV.put(post:meta:…),status=publishedposts:indexsite:lastPublishedAt没有第 7 步「调用 CDN purge」。
索引更新可用版本号 / etag 做乐观锁;失败则重试。KV 无跨键事务时,可加定时 reconcile 扫 Blob 修索引。
1后台写 KV/Blob 成功
2 │
3 ▼
4访客刷新 / 新开 /posts/xxx 或 /
5 │
6 ▼
7Pages / 函数执行 SSR ──读──► KV + Blob
8 │
9 ▼
10返回本次渲染的 HTML要点:
Cache-Control: private, no-store 或仅浏览器短缓存(按你需求)。s-maxage=3600 之类把 SSR 结果又塞回「静态 CDN 线」(除非你明确接受「又要考虑失效」)。/api/updates?since=…(读 site:lastPublishedAt 或差量摘要)。那是 性能优化分支,会把模型变成「SSR + 短时缓存」:
| 方案 | 说明 | 建议 |
|---|---|---|
同域 /admin | 同源、部署一体 | 个人站首选 |
| 独立 admin 域 | 权限隔离 | 多编辑再用 |
| 外部 CMS | 快,但数据不在你 KV | 仅原型 |
publishAt/admin*、/api/admin/* 双层拦截1/ → SSR,读 posts:index
2/posts/[slug] → SSR,读 meta + Blob
3/tags/[tag] → SSR
4/about → 可纯静态 prerender(改得少)
5/admin/* → 后台,no-store
6/api/admin/* → 边缘函数,写存储
7/api/updates → 公开,只读 lastPublishedAt 等Markdown:remark-gfm + 代码高亮 + rehype-sanitize。
与现有 Hugo Teek:可并行域名;用脚本把旧 content/ 灌进 Blob,不必一天切完。
1blog-astro/
2├── apps/web/ # Astro 前台 + /admin
3├── apps/edge-api/ # 边缘函数(若需独立目录)
4├── packages/shared/ # Zod、KV key 常量
5├── scripts/migrate-*.mjs
6└── .cnb/workflows/deploy.yml原则:
JWT_SECRET、KV/Blob/COS 凭证等回滚:
v{n} 恢复为 latest,更新 meta/index —— 仍不用刷 HTML CDNreturn html)不把「HTML CDN 刷新 API」列为 SSR 发文前置条件。
若暂时只有「静态 Pages + 函数」:
| 维度 | Hugo SSG + CDN | Astro SSR + KV/Blob |
|---|---|---|
| 发文 | 易触发整站构建 | 写存储即可 |
| 实时 | 构建 + 静态分发 | 请求时读库渲染 |
| 「刷缓存」 | 静态 HTML 常要面对 | 主路径不需要 |
| 主题 | Teek 已成熟 | 需移植或重做 |
| 后台 | 可接现有 admin 改对接方式 | 原生适配写 API |
折中:内容先上 KV/Blob,Hugo 构建改为拉取远程再 SSG——能复用主题,但实时性仍差一截,且会回到静态分发语义。要「后台秒开」仍以 SSR 读存储为干净。
PUT 一段 KV,另开路由 SSR/Response 读出来展示POST 发布写 Blob + 更新 index/admin 编辑器纯 SSR 每请求打 KV/Blob,个人博客流量通常可接受。若以后 QPS 上来:
| 层 | 选型 |
|---|---|
| 框架 | Astro + TypeScript(SSR) |
| 边缘 | EdgeOne Pages SSR 与/或边缘函数 |
| 数据 | KV + Blob(或 COS) |
| 仓库 / CI | CNB(只部署代码) |
| 编辑器 | Bytemd / TipTap |
| 校验 | Zod |
| 评论 | Twikoo(与内容存储解耦) |
| 风险 | 对策 |
|---|---|
| EO 对 Astro SSR 支持不完整 | 阶段 0 验证;不行则函数直出 HTML(仍是请求时渲染) |
| KV 写后读延迟 | 先知产品语义;必要时间指数退避重试读或版本号 |
误给动态 HTML 加长 s-maxage | Code Review 响应头;监控「发布了还看见旧页」 |
| 主题迁移量大 | 并行域名灰度 |
1// POST /api/admin/posts/:slug/publish
2export async function onRequest(ctx) {
3 await requireAdmin(ctx);
4 const { slug } = ctx.params;
5 const body = await ctx.request.json();
6
7 const blobKey = `content/posts/${slug}/latest.md`;
8 await blob.put(blobKey, body.markdown, {
9 httpMetadata: { contentType: 'text/markdown' },
10 });
11
12 const meta = {
13 title: body.title,
14 tags: body.tags,
15 cover: body.cover,
16 status: 'published',
17 updated: new Date().toISOString(),
18 blobKey,
19 version: Date.now(),
20 };
21 await kv.put(`post:meta:${slug}`, JSON.stringify(meta));
22
23 const index = JSON.parse((await kv.get('posts:index')) || '[]');
24 await kv.put('posts:index', JSON.stringify(upsertIndex(index, {
25 slug,
26 title: meta.title,
27 date: meta.updated,
28 tags: meta.tags,
29 })));
30 await kv.put('site:lastPublishedAt', meta.updated);
31
32 // 到此即发布完成。不调用任何「刷新 HTML CDN」。
33 return Response.json({ ok: true, slug, updated: meta.updated });
34} 1---
2export const prerender = false; // 必须 SSR,不要预渲染成静态
3const slug = Astro.params.slug;
4const meta = await kv.get(`post:meta:${slug}`, 'json');
5if (!meta || meta.status !== 'published') {
6 return Astro.redirect('/404');
7}
8const md = await blob.get(meta.blobKey).text();
9const html = await renderMarkdown(md);
10
11// 动态页:避免被当成长期公共 CDN 静态资源
12Astro.response.headers.set('Cache-Control', 'private, no-store');
13---
14<article set:html={html} />| 称呼 | 含义 |
|---|---|
| SSR | 请求时服务端(或边缘)渲染,读的是当前存储 |
| SSG | 构建时生成静态 HTML,常经 CDN 分发 |
| KV / Blob | 内容源;实时的真相来源 |
| CNB | 代码与主题 CI,不是发文通道 |
| 刷缓存 / purge | 静态 CDN 语义;非本方案 SSR 发文步骤 |
纠正要点回顾:上一版把「发布后 purge」写进 SSR 主路径是错误类比。SSR 实时 = 读最新存储并渲染;Pages/函数动态响应默认不按「静态 CDN 刷缓存」那条线来理解。
日历 · 精选 · 友链 · 更多
如果内容对你有帮助,欢迎请我喝杯咖啡 ☕



One的公众号
爱折腾博客的小白