Next.js调用MongoDB遇Module not found: Can't resolve 'dns'错误求助
问题描述
开发React(Next.js)应用时,访问路由/factura/api/invoices/${invoiceId}并点击编辑按钮,本该提交信息到MongoDB并返回成功,却出现以下错误:
./node_modules/mongodb/lib/cmap/auth/gssapi.js:4:0
Module not found: Can't resolve 'dns'Import trace for requested module:
./node_modules/mongodb/lib/index.js
./pages/facturas/api/edit/[invoiceId]/index.jshttps://nextjs.org/docs/messages/module-not-found
已尝试重装MongoDB、检查路由及MongoDB凭证,均无问题。之前代码正常,调整文件夹结构后出错,将文件夹移回/pages目录后恢复正常。需明确错误原因,以及如何区分前后端代码。
相关代码
前端更新逻辑(位于/facturas/edit/[invoiceId]文件夹)
const updateInvoice = async (invoiceId, status) => { try { const res = await fetch(`/facturas/api/edit/${invoiceId}`, { method: 'PUT', headers: { "Content-Type": "application/json" }, body: JSON.stringify({ senderStreet: senderStreet, senderCity: senderCity, senderPostalCode: senderPostalCode, senderCountry: senderCountry, clientName: clientName, clientEmail: clientEmail, clientStreet: clientStreet, clientCity: clientCity, clientPostalCode: clientPostalCode, clientCountry: clientCountry, description: description, createdAt: createdAt, paymentDue: createdAt, paymentTerms: paymentTerms, status: status, items: items, total: totalAmount }) }) const data = await res.json() router.push(`/facturas/invoices/${invoiceId}`) toast.success(data.message) } catch (error) { toast.error("Something is wrong") console.log(error) } }
后端API逻辑(原位于非pages目录的API文件夹,移至pages后恢复正常)
import { MongoClient, ObjectId } from "mongodb"; async function handler(req, res) { const { invoiceId } = req.query; const client = await MongoClient.connect('mongodb+srv://test:test@cluster0.uusfifl.mongodb.net/invoices?retryWrites=true&w=majority', { useNewUrlParser: true }); const db = client.db(); const collection = db.collection("allInvoices"); if (req.method === "PUT") { await collection.updateOne( { _id: ObjectId(invoiceId), }, { $set: { senderAddress: { street: req.body.senderStreet, city: req.body.senderCity, postalCode: req.body.senderPostalCode, country: req.body.senderCountry, }, clientName: req.body.clientName, clientEmail: req.body.clientEmail, clientAddress: { street: req.body.clientStreet, city: req.body.clientCity, postalCode: req.body.clientPostalCode, country: req.body.clientCountry, }, createdAt: req.body.createdAt, paymentDue: req.body.createdAt, paymentTerms: req.body.paymentTerms, description: req.body.description, status: req.body.status, items: req.body.items, total: req.body.total, }, } ); res.status(200).json({ message: "Invoice updated successfully" }); } client.close(); } export default handler;
错误原因
Next.js的核心规则是:只有pages/api目录下的文件会被当作后端API路由处理,在Node.js环境运行;如果把API文件放在pages目录外,Next.js会将其当作前端代码打包,在浏览器环境中运行。
浏览器环境不支持Node.js的内置模块(比如dns),而MongoDB驱动依赖这些Node.js专属模块,所以当API代码被当作前端代码打包时,就会出现找不到dns模块的错误。将文件夹移回pages目录后,API文件回到pages/api路径下,Next.js按后端逻辑处理,在Node.js环境运行,错误自然消失。
如何区分前后端代码
- 后端API代码:必须放在
pages/api(Next.js 12及以前)或app/api(Next.js 13+ App Router)目录下,这些文件会被编译成独立的后端接口,运行在Node.js环境,可以直接访问数据库、调用Node.js内置模块。 - 前端代码:除上述API目录外的
pages/app下的文件、components/public等目录下的代码,都会被打包到浏览器端运行,只能通过fetch/axios调用后端API,不能直接操作数据库或使用Node.js内置模块。
内容的提问来源于stack exchange,提问作者Luis David Fuquene Charry

