ByteNoteByteNote

字节笔记本

2026年5月3日

TanStack Start - ISR 增量静态再生成

API中转
¥120

从 CDN 提供静态生成的内容,同时在后台定期重新生成。ISR 给你静态网站的性能优势,同时保持动态内容的新鲜度。TanStack Start 的 ISR 方法利用与任何 CDN 兼容的标准 HTTP 缓存头。

什么是 ISR

增量静态再生成(ISR)允许你从 CDN 提供静态生成的内容,同时在后台定期重新生成。核心概念:

  1. 静态预渲染: 页面在构建时生成
  2. CDN 缓存: 缓存头控制 CDN 缓存 HTML 的时间
  3. 重新验证: 缓存过期后,下一个请求触发重新生成
  4. Stale-While-Revalidate: 在后台获取新数据时提供过期内容

缓存头策略

使用带有 max-ages-maxage 指令的 Cache-Control 头:

tsx
// routes/blog/posts/$postId.tsx
export const Route = createFileRoute('/blog/posts/$postId')({
  loader: async ({ params }) => {
    const post = await fetchPost(params.postId)
    return { post }
  },
  headers: () => ({
    'Cache-Control':
      'public, max-age=3600, s-maxage=3600, stale-while-revalidate=86400',
  }),
})

Cache-Control 指令

指令描述
public响应可以被任何缓存缓存
max-age=3600内容在 3600 秒内是新鲜的
s-maxage=3600覆盖共享缓存(CDN)的 max-age
stale-while-revalidate=86400在后台重新验证时提供过期内容最多 24 小时
immutable内容永远不会更改

与服务端函数的 ISR

服务端函数也可以设置缓存头:

tsx
// routes/api/products/$productId.ts
export const Route = createFileRoute('/api/products/$productId')({
  server: {
    handlers: {
      GET: async ({ params }) => {
        const product = await db.products.findById(params.productId)
        return Response.json(
          { product },
          {
            headers: {
              'Cache-Control': 'public, max-age=300, stale-while-revalidate=600',
              'CDN-Cache-Control': 'max-age=3600',
            },
          },
        )
      },
    },
  },
})

按需重新验证

通过 CDN 的 API 触发缓存清除:

tsx
// routes/api/revalidate.ts
export const Route = createFileRoute('/api/revalidate')({
  server: {
    handlers: {
      POST: async ({ request }) => {
        const { path, secret } = await request.json()
        if (secret !== process.env.REVALIDATE_SECRET) {
          return Response.json({ error: 'Invalid token' }, { status: 401 })
        }
        await fetch(
          `https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/purge_cache`,
          {
            method: 'POST',
            headers: {
              Authorization: `Bearer ${CF_API_TOKEN}`,
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({ files: [`https://yoursite.com${path}`] }),
          },
        )
        return Response.json({ revalidated: true })
      },
    },
  },
})

CDN 特定配置

CDN特定头用途
CloudflareCDN-Cache-Control更精细的 CDN 控制
Netlify_headers 文件静态配置
Vercels-maxageEdge Network 优化

与客户端缓存结合

TanStack Router 的内置缓存控制与 CDN 缓存配合使用:

tsx
export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => fetchPost(params.postId),
  headers: () => ({
    'Cache-Control': 'public, max-age=3600, stale-while-revalidate=86400',
  }),
  staleTime: 60_000,   // 客户端上数据保持新鲜 60 秒
  gcTime: 5 * 60_000,  // 在内存中保留 5 分钟
})

常见 ISR 模式

内容类型max-agestale-while-revalidatestaleTime
博客文章3600s (1h)604800s (7d)300s (5m)
产品页面300s (5m)3600s (1h)30s
落地页86400s (1d)604800s (7d)3600s (1h)
用户数据60s030s

缓存头速查

指令用途值示例
public允许 CDN 缓存-
private仅浏览器缓存-
max-age新鲜时间3600 (1h)
s-maxageCDN 覆盖7200 (2h)
stale-while-revalidate后台重新验证86400 (1d)
分享: