Next.js高级特性:预览模式

在Pages文档和Data Fetching文档中,我们讨论了如何使用和在构建时预渲染页面(静态生成)。getStaticPropsgetStaticPaths

当页面从无头CMS提取数据时,“静态生成”很有用。但是,当您在无头CMS上编写草稿并希望立即在页面上预览草稿时,这是不理想的。您希望Next.js在请求时而不是在构建时呈现这些页面,并获取草稿内容而不是已发布的内容。您只希望Next.js在这种情况下绕过Static Generation。

Next.js具有称为“预览模式”的功能,可以解决此问题。以下是有关如何使用它的说明。

步骤1.创建和访问预览API路线

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

首先,创建一个预览API路线。它可以具有任何名称-例如pages/api/preview.js(或.ts使用TypeScript)。

在此API路由中,您需要调用setPreviewData响应对象。for的参数setPreviewData应该是一个对象,并且可以使用getStaticProps(稍后会有更多介绍)。现在,我们将使用{}

export default function handler(req, res) {
  // ...
  res.setPreviewData({})
  // ...
}

res.setPreviewData在打开预览模式的浏览器上设置一些cookie。对包含这些cookie的对Next.js的任何请求都将被视为预览模式,并且静态生成的页面的行为将发生变化(稍后会对此进行更多介绍)。

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

// A simple example for testing it manually from your browser.
// If this is located at pages/api/preview.js, then
// open /api/preview from your browser.
export default function handler(req, res) {
  res.setPreviewData({})
  res.end('Preview mode enabled')
}

如果使用浏览器的开发人员工具,您会注意到,将在此请求上设置__prerender_bypass__next_preview_datacookie。

从您的Headless CMS安全地访问它

实际上,您希望从无头CMS安全地调用此API路由。具体步骤会因您所使用的无头CMS而有所不同,但这是您可以采取的一些常见步骤。

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

首先,您应该使用所选的令牌生成器创建秘密令牌字符串。仅您的Next.js应用和无头CMS才知道此秘密。此秘密可防止无权访问您的CMS的人访问预览URL。

其次,如果您的无头CMS支持设置自定义预览URL,请指定以下内容作为预览URL。(这假设您的预览API路由位于pages/api/preview.js。)

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

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

最后,在预览API路线中:

  • 检查密码是否匹配以及slug参数是否存在(如果不存在,则请求将失败)。
  • 致电res.setPreviewData
  • 然后将浏览器重定向到所指定的路径slug。(以下示例使用307 redirect)。
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 preview mode from being enabled
  if (!post) {
    return res.status(401).json({ message: 'Invalid slug' })
  }

  // Enable Preview Mode by setting the cookies
  res.setPreviewData({})

  // 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以支持预览模式。

如果您请求的页面getStaticProps设置了(通过res.setPreviewData)设置了预览模式Cookie ,则将getStaticProps请求时(而不是在构建时)调用该页面。

此外,将使用以下context对象调用该对象:

  • context.preview会的true
  • context.previewData将与用于的参数相同setPreviewData
export async function getStaticProps(context) {
  // If you request this page with the preview mode cookies set:
  //
  // - context.preview will be true
  // - context.previewData will be the same as
  //   the argument used for `setPreviewData`.
}

我们res.setPreviewData({})在预览API路由中使用过,因此context.previewData将是{}getStaticProps如有必要,您可以使用它来将会话信息从预览API路由传递到。

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

获取预览数据

您可以getStaticProps基于context.preview和/或更新以获取不同的数据context.previewData

例如,您的无头CMS可能具有不同的草稿帖子API端点。如果是这样,您可以使用context.preview来修改API端点URL,如下所示:

export async function getStaticProps(context) {
  // If context.preview is true, append "/preview" to the API endpoint
  // to request draft data instead of published data. This will vary
  // based on which headless CMS you're using.
  const res = await fetch(`https://.../${context.preview ? 'preview' : ''}`)
  // ...
}

就是这样!如果您从无头CMS或通过手动访问预览API路由(使用secretslug),则现在应该可以看到预览内容。而且,如果您在不发布的情况下更新草稿,则应该能够预览草稿。

# Set this as the preview URL on your headless CMS or access manually,
# and you should be able to see the preview.
https://<your-site>/api/preview?secret=<token>&slug=<path>

更多细节

清除预览模式的Cookie

默认情况下,没有为预览模式Cookie设置有效期,因此,关闭浏览器时,预览模式结束。

要手动清除预览cookie,您可以创建一个调用的API路由,clearPreviewData然后访问该API路由。

export default function handler(req, res) {
  // Clears the preview mode cookies.
  // This function accepts no arguments.
  res.clearPreviewData()
  // ...
}

指定预览模式的持续时间

setPreviewData接受一个可选的第二个参数,该参数应该是一个options对象。它接受以下密钥:

  • maxAge:指定预览会话要持续的时间(以秒为单位)。
setPreviewData(data, {
  maxAge: 60 * 60, // The preview mode cookies expire in 1 hour
})

previewData 大小限制

您可以将对象传递给setPreviewData并在中使用它getStaticProps。但是,由于数据将存储在Cookie中,因此存在大小限制。当前,预览数据限制为2KB。

适用于 getServerSideProps

预览模式也适用getServerSideProps。它也将在context包含preview和的对象上可用previewData

使用API​​路由

API路由将有权访问请求对象previewpreviewData在该对象下。例如:

export default function myApiRoute(req, res) {
  const isPreview = req.preview
  const previewData = req.previewData
  // ...
}

Unique per next build

完成时,绕过cookie值和用于加密previewData更改的私钥都将next build被使用。这样可以确保无法猜测旁路cookie。

作者:terry,如若转载,请注明出处:https://www.web176.com/nextjs/2447.html

(0)
打赏 支付宝 支付宝 微信 微信
terryterry
上一篇 2021年4月20日 下午3:13
下一篇 2021年4月20日 下午4:14

相关推荐

发表回复

登录后才能评论