introduction
预览模式,在例如博客文章等相关地方,或者预设主题时使用的应该非常多 …
我们之前学习了如何使用预渲染(例如静态生成), 但是对于我们使用预览模式来说,这不方便,,因为有些时候我们需要页面立即将修改的东西进行预览,并且这些页面是在请求时渲染而不是构建时(并且是抓取草案内容而不是发布的内部),所以我们就需要使用预览模式解决这个问题 ..
第一步,创建并访问预览API 路由
假设,预览API 路由名称为: pages/api/preview.js
或者.ts
在API 路由中,我们需要设置setPreviewData
在响应体对象上,这个setPreviewData
的参数应该是一个对象,并且它应该能够被getStaticProps
所使用,现在它是一个{}
res.setPreviewData
设置某些Cookie在浏览器上(在预览模式中会打开),任何包含这些cookies的发送给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 将被在这个请求上设置 ..
从无头CMS上安全的访问它
事实上,你想要从无头CMS上安全的调用API 路由,这特定的步骤将会依赖于你使用的CMS,但是这里有一些常见步骤需要你注意:
这些步骤假设无头CMS(你能够支持配置自定义的预览URL),如果不可能,你仍然能够使用这个安全访问预览URL …
但是你需要手动的构造并访问这个预览URL …
- 首先,你需要创建一个加密token 字符串(通过你选择的token 生成器),这个密钥仅仅能够被你的next.js app 和CMS 知道,这个密钥阻止了不能从预览URL 上访问MCS …
- 第二,如果你的CMS 支持设置自定义的预览URL,指定如下作为预览URL(假设你的预览API 路由位于·
pages/api/preview.js
)
https://<your-site>/api/preview?secret=<token>&slug=<path>
- 站点 部署的域名
- token 生成的安全加密token
- 路径 想要进行预览的页面路径,如果你想要预览
/posts/foo
,然后你应该使用&slug=/posts/foo
你的无头CMS可能允许你包括一个变量在预览URL 中,因此path
能够基于CMS的数据动态设置 …,例如slug=/posts/{entry.fields.slug}
最终,在预览API 路由中:
- 检查secret是否匹配并且
slug
参数存在,如果不存在请求失败) - 调用
res.setPreviewData
- 然后重定向浏览器到由
slug
指定的路径 (例如这个示例使用307 重定向) ..)
如果成功,浏览器将重定向到你想预览的路径(使用已经被设置的预览模式 cookies) ..
第二步,更新getStaticProps
这一步更新getStaticProps
来支持预览模式 ..
如果你请求一个页面(它有一个使用了预览模式Cookies设置的getStaticProps
),那么getStaticProps
将会在请求时进行调用(而不是构建时) …
因此,它将被调用且有一个context
对象能够被使用
context.preview
= truecontext;.previewData
将等价于setPreviewData
设置的参数 …
于是当我们使用res.setPreviewData({})
在预览API 路由中,那么context.previewData
将会是{}
,你能够使用它从预览API 路由传递会话信息到 getStaticProps
(如果有必要) ..
如果你还使用getSaticPaths
,那么context.params
将也是可用的 ..
抓取预览数据
现在我们可以基于context
对象来抓取不同的数据 更新getStaticProps
,举个例子,如果无头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' : ''}`)
// ...
}
这就是全部了,如果你访问预览API 路由(使用secret
以及 slug
)从无头CMS或者手动访问,你应该现在能够查看预览内容了,并且如果你更新你的草案而不是发布,你应该能够预览草案 …
这里的意思就是从CMS 发送请求到API 预览路由(或者手动发送请求) 应该能够看到预览内容 ….
更多细节
在渲染next/router
时暴露了一个isPreview
标志,查看路由对象文档了解更多 …
清理预览模式cookies
默认对于预览模式的cookie没有过期时间,因此在浏览器关闭时预览会话将会结束 ..
为了手动清理预览模式cookie,创建一个API 路由然后调用即可 ..
// pages/api/clear-preview-mode-cookies.js
export default function handler(req, res) {
res.clearPreviewData()
}
然后,发送一个请求到/api/clear-preview-mode-cookies
执行API 路由即可清理..
如果通过next/link
调用这个路由,你必须传递prefetch={false}
去阻止在链接预抓取之前调用clearPreviewData
….
指定预览模式的周期
setPreviewData
可以携带第二个可选的参数,它们应该是一个可选对象,接收如下的属性
max-Age
预览会话的最大时间(秒)path
指定cookie应该应用在那个路径之下,默认是/
,对全部路径启用预览模式 …
setPreviewData(data, {
maxAge: 60 * 60, // The preview mode cookies expire in 1 hour
path: '/about', // The preview mode cookies apply to paths with /about
})
previewData
尺寸限制
你能够传递一个对象到 setPreviewData
并且它可以在getStaticProps
中可用,然后由于这些数据是存储在cookie中,那么存在容量尺寸限制,目前预览数据的尺寸为2KB …
与getServerSideProps
协同工作
这个预览模式同样可以和它工作,它同样可以包含一个context 对象(内容一致) ..
与API 路由协同工作
API 路由能够在请求对象中访问preview
以及 previewData
..
export default function myApiRoute(req, res) {
const isPreview = req.preview
const previewData = req.previewData
// ...
}
每一次next build
独一无二
绕过 Cookie 值和用于加密预览的私钥在next build
完成时都会更改。这可确保无法猜到 Cookie 内容。
在基于Http 的本地浏览器上测试预览模式需要允许第三方cookies 以及本地存储访问 …
也就是next 对于cookie中存放的内容进行了私钥加密, 那么保障了一定的安全 …