Next.js 基于文件拉取的博客如何实现手动缓存revalidate?
解决方案
你需要的是 Next.js 提供的**按需重验(On-Demand Revalidation)**功能,完全不需要固定时间间隔刷新缓存,只有你主动触发时才会重新拉取posts文件内容生成新页面。
注:按需重验功能需要 Next.js 12.1 及以上版本支持,如果你的项目版本较低需要先升级。
实现步骤
第一步:创建重验API路由
在pages/api目录下新建revalidate.js文件,代码如下:
export default async function handler(req, res) { // 建议加密钥校验,防止别人恶意调用重验接口 if (req.query.secret !== process.env.REVALIDATE_SECRET) { return res.status(401).json({ message: '无效的访问权限' }) } try { // 这里填你博客页面的路由,博客在首页就填'/',在/blog路径就填'/blog' await res.revalidate('/') return res.json({ revalidated: true }) } catch (err) { return res.status(500).send('重验失败') } }
你需要在项目环境变量里配置REVALIDATE_SECRET为自定义的密钥,避免接口被滥用。
第二步:修改原有页面的getStaticProps配置
把原来的固定短周期revalidate:60调整为长周期兜底即可,也可以直接删除(删除后只有手动触发才会更新,无兜底刷新):
import path from 'path' import { promises as fs } from 'fs' function Blog ({ posts }) { return ( <ul> {posts.map((post, key) => ( <li key={key}> <h3>{post.filename}</h3> <p>{post.fileContent}</p> </li> ))} </ul> ) } export async function getStaticProps () { const postsDirectory = path.join(process.cwd(), 'posts') const filenames = await fs.readdir(postsDirectory) const posts = filenames.map(async (filename) => { const filePath = path.join(postsDirectory, filename) const fileContent = await fs.readFile(filePath, 'utf8') return { filename, fileContent } }) return { props: { posts: await Promise.all(posts) }, // 留个一天的长周期作为兜底,也可以删掉这行完全禁用定时重验 revalidate: 86400 } } export default Blog
第三步:posts目录变动时自动触发重验
你可以通过两种方式实现posts文件改动时自动触发缓存刷新:
- 本地开发/手动更新场景:用
nodemon监听posts目录,文件变动时自动调用重验接口,示例脚本如下:
// 可以存为scripts/watch-posts.js const nodemon = require('nodemon') const axios = require('axios') nodemon({ watch: './posts', ext: 'md markdown txt' // 替换为你实际使用的博客文件后缀 }) nodemon.on('change', async () => { try { await axios.get('https://你的域名/api/revalidate?secret=你设置的密钥') console.log('博客缓存已更新') } catch (e) { console.log('重验失败', e) } })
- CI/CD自动部署场景:在你的部署流程里加一步调用重验接口的请求,只要有新的文章提交到仓库,部署完成后自动触发重验即可。
备选方案
如果你的博客更新频率极低,也可以直接删掉revalidate配置,每次新增/修改文章后重新部署整个项目,全量构建生成新的静态页面,也能达到更新内容的效果,缺点是每次更新都需要重新构建,不如按需重验方便。
内容的提问来源于stack exchange,提问作者ozgrozer
相关产品推荐
相关产品推荐

