For AI/LLM: site guide at /llms.txt
博客更新小结:Nuxt 手动刷新 Vercel ISR 缓存
Outline

博客更新小结:Nuxt 手动刷新 Vercel ISR 缓存


󰈈 6min 2026/7/4󰚰 2026/7/4

折腾了一个月,把之前既要SSR,文章又是静态生成的不伦不类的博客改成了动态博客。总结下我在开发时遇到的技术问题和一些改动。

由于部分人梯子的问题,Git 卡片会触发429,旧主题就干脆把 Git 卡片SSR渲染到页面上,避免了部分人无法看的问题,同时SSR也可以避免每个人打开页面都调用API对服务器的开销。

虽然我旧主题有着用于SSR的后端,但编写思路还是照着静态写的:

  • 文章更新完要重新编译
  • 评论区是页面打开后才加载的

静态主题有着不需要后端的轻便性,但是我已经有SSR后端了,这个轻便性的优势就少了很多,但静态页面固有的缺陷它仍然存在:

  • 每次编译要重新生成全部文章,开销较大,动态的只需要更新新文章
  • 即便设置了url携带评论id时,自动跳转到对应评论的功能,但由于评论没有加载出来的问题,还需要等待一定时间

思来想去,不如改成纯动态的了

相对于静态博客编译完立刻可以看到,动态博客在文章改动后,可能由于 CDN 缓存,变动并不能立刻显示出来。这点我是不能接受的,文章更新完,手动刷新缓存对我来说是刚需。

Next用户有 revalidatePath 可以用,但我不会 react ,查阅Nuxt网站也没见有类似的东西。

参考 Vercel 的 Demo 得知,可以为每一个页面设置一个 bypassToken ,然后携带 x-prerender-revalidate: bypassToken 作为请求头,以 GET 或 'POST' 方法发送http请求,
如果请求发起成功的话,收到的的响应头里会包含 x-vercel-cache: REVALIDATED

vercel/example
avatarOn-Demand Incremental Static Regeneration (ISR)

对于 Nuxt 而言,你可以在它的配置文件里指定 bypassToken ,然后它生成的所有ISR页面都会使用这个值作为 bypassToken

TypeScript
export default defineNuxtConfig({
    nitro: {
        vercel: {
            config: {
                bypassToken: 你的 bypassToken,
            },
        },
    },
})

服务端的 /server/api/server/routes 更新起来比较方便。直接对他们发http请求就行了。

INFO

Nuxt 调用内部 Api 时,会转化为函数调用,根本不执行http请求,所以对 Api 进行缓存意义不大,这个主要还是对 /server/routes 有用。

TIP

以下内容是我的一些经验,我并没有查到相关文档。

前端 App 更新起来会麻烦些。需要先更新你的页面,然后再更新payload,不然会导致收到的网页上新的,但拿到的payload是旧的,又给你渲染成旧页面,顺便给你一个水合失败报错。 个人推测在 SSR 新网页时生成了新的 payload 数据,但这个数据由于旧的 payload 缓存没过时,它并不会被展示。

以下是我刷新前端页面缓存的代码,可以参考下。

TypeScript
/**
 * 更新指定路由的ISR缓存
 * @param event H3事件
 * @param route 路由
 */
export async function revalidate(event: H3Event, route: string): Promise<void> {
    const url = getRequestURL(event)
    const res = await $fetch.raw(`${url.origin}${route}`, {
        headers: { 'x-prerender-revalidate': useRuntimeConfig(event).bypassToken },
    })
    const cacheStatus = res.headers.get('x-vercel-cache')

    if (cacheStatus !== 'REVALIDATED') {
        throw new Error(
            `Revalidation failed for "${url.origin}${route}": x-vercel-cache is "${cacheStatus}"`,
        )
    }
}

/**
 * 更新指定页面的ISR缓存
 * @param event H3事件
 * @param route 路由
 */
export async function revalidatePage(event: H3Event, route: string): Promise<void> {
    const appId = useRuntimeConfig().app.buildId ?? ''
    const payloadRoute = `${route}/_payload.json?${appId}`

    await revalidate(event, route)
    await revalidate(event, payloadRoute)
}

WARNING

不论是前端还是服务端更新时需要使用带上域名的完整的路径,使用路径的话会被视为 Nuxt 内部路由,转化为函数调用。

Nuxt Content的Markdown解析结果和Nuxt Mdc一模一样,两者功能有一定的重叠。 我的评论区已经在用Nuxt Mdc做动态解析了,而且我也有自己进行 Markdown 管理来进行缓存的需求,使用Nuxt Mdc可以完全替代Nuxt Content。

由于我的博客现在成动态的了,文章原文在CMS里外人不能随便访问了。为此提供了原始文件链接进行补偿。同时原始文件可以帮助各种 Agent 更好的阅读文件。

llms.txt是帮助 Agent 快速了解该网站的手段之一。这次更新新加了llms.txt文件,并且添加了一些引导。

llms-txt
avatarThe /llms.txt file

INFO

本文章采用     CC BY-NC-SA 4.0 协议进行许可。如需转载,请注明出处。
查看原始Markdown
加载ing
c9287fa
Post.vue
utf-8
TOP
1:1