Next.js集成Storyblok:隐藏API密钥引发客户端报错的方案咨询
我在用Next.js搭配Storyblok,采用react-next-boilerplate模板时发现,模板将预览令牌直接硬编码在_app.js的storyblokInit中,等于公开了敏感令牌:
storyblokInit({ accessToken: "your-preview-token", use: [apiPlugin], components, });
若改用客户端无法访问的服务端环境变量,客户端会触发错误:
You need to provide an access token to interact with Storyblok API
推测原因是组件使用了依赖全局Storyblok状态的StoryblokComponent,下面针对四个方案逐一分析可行性:
方案1:忽略该错误?
如果你的场景确实是仅用Storyblok做组件渲染,所有数据均通过服务端获取(符合SSG/ISR逻辑),且当前渲染功能完全正常,那么忽略这个错误是可行的。因为客户端的storyblokInit没有令牌,只是无法发起API请求,但你本来就不需要客户端拉取数据,所有渲染用的数据已经在服务端预取完成。不过要注意监控日志,避免这个错误干扰其他问题的排查。
方案2:直接公开预览令牌?
不建议这么做。预览令牌(preview token)即便主要用于预览环境,一旦公开,恶意用户可利用它访问你的Storyblok空间数据,甚至修改内容(取决于令牌权限)。哪怕是静态站点,数据泄露也存在风险,这个方案安全性极低,直接排除。
方案3:创建服务端和客户端两个独立令牌?
这是最规范的解决方案。Storyblok支持创建不同权限的令牌:
- 服务端私有令牌:用于服务端数据获取(比如
getStaticProps、getServerSideProps),需存储在服务端环境变量中,绝对不能暴露给客户端。 - 客户端预览令牌:用于客户端预览模式(比如Storyblok的实时编辑预览),可安全暴露给客户端,因为它通常只有只读权限,且仅能访问预览版本内容。
你可以修改storyblokInit的逻辑,区分客户端和服务端环境:
// _app.js storyblokInit({ accessToken: typeof window !== 'undefined' ? process.env.NEXT_PUBLIC_STORYBLOK_PREVIEW_TOKEN // 客户端用公开的预览令牌 : process.env.STORYBLOK_PRIVATE_TOKEN, // 服务端用私有令牌 use: [apiPlugin], components, });
这样既满足StoryblokComponent对全局状态的依赖,又能保证服务端令牌不泄露。
方案4:将令牌设为process.env.STORYBLOK_API_KEY || "NULL"?
这个方案能消除错误,但属于投机取巧的临时办法。虽然客户端不会报错,但如果后续代码不小心触发了客户端API请求(比如误加了客户端数据获取逻辑),会因令牌无效而失败,且这种写法不够清晰,不利于后续维护。如果没有其他更好的临时方案,可作为权宜之计,但长期来看还是推荐方案3。
关于“组件渲染与数据获取整合到同一函数”的疑惑
Storyblok的React SDK这样设计,是为了统一服务端和客户端的开发体验:一方面,storyblokInit初始化全局API客户端和组件映射,服务端可用它拉取数据,客户端可用它实现实时预览(比如编辑时自动刷新内容);另一方面,StoryblokComponent依赖全局状态来解析组件数据、处理预览模式的交互(比如高亮编辑区域)。这个设计兼顾了静态生成和实时编辑场景,但确实会给纯静态站点开发者带来令牌安全的困扰。
内容的提问来源于stack exchange,提问作者fweth

