跳至内容

草稿模式

页面文档数据获取文档中,我们讨论了如何在构建时(**静态生成**)使用getStaticPropsgetStaticPaths预渲染页面。

当您的页面从无头 CMS 获取数据时,静态生成非常有用。但是,当您在无头 CMS 上撰写草稿并希望立即在页面上查看草稿时,它并不理想。您希望 Next.js 在**请求时**而不是构建时渲染这些页面,并获取草稿内容而不是已发布的内容。您希望 Next.js 仅在此特定情况下绕过静态生成。

Next.js 具有一个名为**草稿模式**的功能,可以解决此问题。以下是如何使用它的说明。

步骤 1:创建并访问 API 路由

如果您不熟悉 Next.js API 路由,请先查看API 路由文档

首先,创建**API 路由**。它可以具有任何名称,例如 pages/api/draft.ts

在此 API 路由中,您需要在响应对象上调用setDraftMode

export default function handler(req, res) {
  // ...
  res.setDraftMode({ enable: true })
  // ...
}

这将设置一个**Cookie**以启用草稿模式。包含此 Cookie 的后续请求将触发**草稿模式**,从而更改静态生成页面的行为(稍后将详细介绍)。

您可以通过手动创建如下所示的 API 路由并从浏览器手动访问它来测试它

pages/api/draft.ts
// simple example for testing it manually from your browser.
export default function handler(req, res) {
  res.setDraftMode({ enable: true })
  res.end('Draft mode is enabled')
}

如果您打开浏览器的开发者工具并访问/api/draft,您会注意到一个名为__prerender_bypass的 Cookie 的Set-Cookie响应头。

从您的无头 CMS 安全地访问它

在实践中,您希望从您的无头 CMS**安全地**调用此 API 路由。具体步骤因您使用的无头 CMS 而异,但以下是一些您可以采取的常见步骤。

这些步骤假设您使用的无头 CMS 支持设置**自定义草稿 URL**。如果不支持,您仍然可以使用此方法来保护草稿 URL,但您需要手动构造和访问草稿 URL。

**首先**,您应该使用您选择的令牌生成器创建一个**秘密令牌字符串**。此秘密仅为您的 Next.js 应用程序和您的无头 CMS 所知。此秘密可以防止没有访问您 CMS 权限的人访问草稿 URL。

**其次**,如果您的无头 CMS 支持设置自定义草稿 URL,请指定以下内容作为草稿 URL。这假设您的草稿 API 路由位于pages/api/draft.ts

终端
https://<your-site>/api/draft?secret=<token>&slug=<path>
  • <your-site> 应为您的部署域名。
  • <token> 应替换为您生成的秘密令牌。
  • <path> 应为要查看的页面的路径。如果要查看/posts/foo,则应使用&slug=/posts/foo

您的无头 CMS 可能会允许您在草稿 URL 中包含一个变量,以便可以根据 CMS 的数据动态设置<path>,如下所示:&slug=/posts/{entry.fields.slug}

**最后**,在草稿 API 路由中

  • 检查秘密是否匹配以及slug参数是否存在(如果不存在,请求应失败)。
  • 调用res.setDraftMode
  • 然后将浏览器重定向到由slug指定的路径。(以下示例使用307 重定向)。
export default async (req, res) => {
  // Check the secret and next parameters
  // This secret should only be known to this API route and the CMS
  if (req.query.secret !== 'MY_SECRET_TOKEN' || !req.query.slug) {
    return res.status(401).json({ message: 'Invalid token' })
  }
 
  // Fetch the headless CMS to check if the provided `slug` exists
  // getPostBySlug would implement the required fetching logic to the headless CMS
  const post = await getPostBySlug(req.query.slug)
 
  // If the slug doesn't exist prevent draft mode from being enabled
  if (!post) {
    return res.status(401).json({ message: 'Invalid slug' })
  }
 
  // Enable Draft Mode by setting the cookie
  res.setDraftMode({ enable: true })
 
  // Redirect to the path from the fetched post
  // We don't redirect to req.query.slug as that might lead to open redirect vulnerabilities
  res.redirect(post.slug)
}

如果成功,则浏览器将重定向到您要查看的路径,并带有草稿模式 Cookie。

步骤 2:更新 getStaticProps

下一步是更新 getStaticProps 以支持草稿模式。

如果您请求一个页面,该页面具有设置了 Cookie 的 getStaticProps(通过 res.setDraftMode),则 getStaticProps 将在**请求时**(而不是在构建时)被调用。

此外,它将使用一个 context 对象进行调用,其中 context.draftMode 将为 true

export async function getStaticProps(context) {
  if (context.draftMode) {
    // dynamic data
  }
}

我们在草稿 API 路由中使用了 res.setDraftMode,因此 context.draftMode 将为 true

如果您也使用 getStaticPaths,则 context.params 也将可用。

获取草稿数据

您可以更新 getStaticProps 以根据 context.draftMode 获取不同的数据。

例如,您的无头 CMS 可能对草稿帖子有不同的 API 端点。如果是这样,您可以修改 API 端点 URL,如下所示

export async function getStaticProps(context) {
  const url = context.draftMode
    ? 'https://draft.example.com'
    : 'https://production.example.com'
  const res = await fetch(url)
  // ...
}

就是这样!如果您从您的无头 CMS 或手动访问草稿 API 路由(使用 secretslug),您现在应该能够看到草稿内容。如果您更新草稿而不发布,您应该能够查看草稿。

在您的无头 CMS 上将此设置为草稿 URL 或手动访问,您应该能够看到草稿。

终端
https://<your-site>/api/draft?secret=<token>&slug=<path>

更多详情

默认情况下,草稿模式会话在浏览器关闭时结束。

要手动清除草稿模式 Cookie,请创建一个调用 setDraftMode({ enable: false }) 的 API 路由。

pages/api/disable-draft.ts
export default function handler(req, res) {
  res.setDraftMode({ enable: false })
}

然后,发送请求到 /api/disable-draft 以调用 API 路由。如果使用 next/link 调用此路由,则必须传递 prefetch={false} 以防止在预取时意外删除 Cookie。

适用于 getServerSideProps

草稿模式适用于 getServerSideProps,并且在 context 对象中可用作 draftMode 键。

注意:在使用草稿模式时,不应设置 Cache-Control 标头,因为它无法被绕过。相反,我们建议使用 ISR

适用于 API 路由

API 路由将能够访问请求对象上的 draftMode。例如

export default function myApiRoute(req, res) {
  if (req.draftMode) {
    // get draft data
  }
}

每次 next build 构建时都唯一

每次运行 next build 时,都会生成一个新的旁路 Cookie 值。

这确保了无法猜测旁路 Cookie。

注意:要在本地通过 HTTP 测试草稿模式,您的浏览器需要允许第三方 Cookie 和本地存储访问。