生产环境MongoDB insertOne()过慢,页面重载无法获取最新数据
问题:Next.js + MongoDB 生产环境插入数据后刷新无法立即看到新记录
我有一个基于MongoDB模板的新Next.js应用,执行简单的insertOne操作后重载页面,本地运行完全正常,但生产环境中这个过程需要几秒,导致页面重载无法获取到最新记录,必须再次刷新页面。我忽略了什么?
前端提交评论的代码
const submitComment = async(e:any) => { e.preventDefault(); try { let response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/addPost`, { method: "POST", body: JSON.stringify({comment}), headers: { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json' } }); response = await response.json(); window.location.reload(); }catch(err: any) { // console.log(`ERROR: ${err}`) } }
页面数据获取逻辑(getStaticProps)
export const getStaticProps: GetStaticProps = async () => { const posts = await getPosts(); return { props: { posts: JSON.parse(JSON.stringify(posts)) }, revalidate: 10 }; };
getPosts() 方法实现
let client; let posts: any; async function init() { try { client = await clientPromise; posts = client.db('hors-service').collection('posts'); } catch (error) { throw new Error('Failed to establish connection to database'); } } ;(async () => { await init() })() export async function getPosts() { try { if(!posts) await init(); const result = await posts .find() .map( (post: { _id: { toString: () => any; }; }) => ({...post, _id: post._id.toString()})) .sort( { _id: -1 }) .toArray(); return result; } catch (error) { return { error: 'Failed to fetch posts'}; } }
MongoDB配置文件
import { MongoClient } from 'mongodb'; if (!process.env.MONGODB_URI) { throw new Error('Please add your Mongo URI to .env.local'); } const uri = process.env.MONGODB_URI; const options = {}; let client; let clientPromise: Promise<any>; declare global { var _mongoClientPromise: Promise<MongoClient>; } if (process.env.NODE_ENV === 'development') { // In development mode, use a global variable so that the value // is preserved across module reloads caused by HMR (Hot Module Replacement). if (!global._mongoClientPromise) { client = new MongoClient(uri, options); global._mongoClientPromise = client.connect(); } clientPromise = global._mongoClientPromise; } else { // In production mode, it's best to not use a global variable. client = new MongoClient(uri, options); clientPromise = client.connect(); } // Export a module-scoped MongoClient promise. By doing this in a // separate module, the client can be shared across functions. export default clientPromise;
问题原因与解决方法
核心原因
你使用了 getStaticProps + revalidate:10 开启了增量静态再生(ISR),生产环境下页面会被静态缓存。即便插入了新数据,页面刷新时大概率加载的还是缓存版本,要等10秒后才会重新生成页面。而本地开发时Next.js默认禁用静态缓存,所以能立即看到新数据。
解决思路1:改用SWR/React Query做客户端数据获取
放弃依赖 getStaticProps 的静态数据,改用客户端数据获取库(比如SWR),每次页面刷新都会从API拉取最新数据:
import useSWR from 'swr'; const fetcher = async () => { const res = await fetch('/api/getPosts'); return res.json(); }; export default function PostsPage() { const { data: posts, error } = useSWR('/api/getPosts', fetcher); if (error) return <div>加载失败</div>; if (!posts) return <div>加载中...</div>; // 渲染posts列表 return ( <div> {posts.map(post => ( <div key={post._id}>{post.comment}</div> ))} </div> ); }
同时新增 pages/api/getPosts.ts 接口:
import clientPromise from '../../lib/mongodb'; export default async function handler(req, res) { const client = await clientPromise; const db = client.db('hors-service'); const posts = await db.collection('posts') .find() .map(post => ({...post, _id: post._id.toString()})) .sort({_id: -1}) .toArray(); res.status(200).json(posts); }
解决思路2:强制触发ISR重新生成页面
在插入数据的API接口(/api/addPost)中,调用Next.js的 revalidatePath 方法强制刷新页面的静态缓存:
// pages/api/addPost.ts import clientPromise from '../../lib/mongodb'; import { revalidatePath } from 'next/cache'; export default async function handler(req, res) { if (req.method !== 'POST') { return res.status(405).json({ message: 'Method Not Allowed' }); } const { comment } = req.body; const client = await clientPromise; const db = client.db('hors-service'); await db.collection('posts').insertOne({ comment, createdAt: new Date() }); // 强制重新生成帖子列表页面(替换成你的实际页面路径) revalidatePath('/'); res.status(200).json({ success: true }); }
这样插入数据后,Next.js会立即重新生成页面的静态版本,用户刷新就能看到新数据,同时保留ISR的缓存优势。
解决思路3:改用getServerSideProps
如果页面不需要静态缓存,直接用 getServerSideProps 代替 getStaticProps,每次页面请求都会从数据库拉取最新数据:
export const getServerSideProps: GetServerSideProps = async () => { const posts = await getPosts(); return { props: { posts: JSON.parse(JSON.stringify(posts)) } }; };
但这种方式会增加服务器负载,适合数据更新频繁且访问量不高的场景。
内容的提问来源于stack exchange,提问作者fumeng
相关产品推荐
相关产品推荐

