在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_data
cookie。
从您的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路由(使用secret
和slug
),则现在应该可以看到预览内容。而且,如果您在不发布的情况下更新草稿,则应该能够预览草稿。
# 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路由将有权访问请求对象preview
并previewData
在该对象下。例如:
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