Next.js中间件连接MongoDB失败,报bson模块未定义属性错误
问题:Next.js中间件连接MongoDB时抛出BSON相关错误
代码示例
import { getValidSubdomain } from '@/lib/getValidSubdomain'; import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' import * as mongoDB from 'mongodb'; let cachedDb: mongoDB.Db = null; export function middleware(req: NextRequest) { const host = req.headers.get('host'); const subdomain = getValidSubdomain(host); console.log({subdomain}) if(!subdomain) return NextResponse.next() console.log({MONGOURL: process.env.MONGO_URL}) mongoDB.MongoClient.connect(process.env.MONGO_URL, { useNewUrlParser: true, useUnifiedTopology: true, }) .then((client) => { const db = client.db(); }) }); // 此处存在语法错误:多余的闭合括号与分号 } export const config = { matcher: '/(.*)', }
报错信息
- error node_modules/bson/lib/bson/symbol.js (2:0) @ <unknown> - error Cannot read properties of undefined (reading 'custom')
原因分析
Next.js中间件默认运行在Edge Runtime环境,官方mongodb驱动依赖的BSON库使用了Edge环境不支持的Node.js内置API(如Symbol.custom这类非标准扩展),导致运行时抛出未定义属性错误。同时原代码存在语法错误,多余的});会导致代码无法正常执行。
解决方案
1. 修复基础语法错误
先移除代码中多余的});,确保代码语法合法:
import { getValidSubdomain } from '@/lib/getValidSubdomain'; import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' import * as mongoDB from 'mongodb'; export function middleware(req: NextRequest) { const host = req.headers.get('host'); const subdomain = getValidSubdomain(host); console.log({subdomain}) if(!subdomain) return NextResponse.next() console.log({MONGOURL: process.env.MONGO_URL}) mongoDB.MongoClient.connect(process.env.MONGO_URL, { useNewUrlParser: true, useUnifiedTopology: true, }) .then((client) => { const db = client.db(); // 添加子域名查询逻辑,例如: // db.collection('subdomains').findOne({ name: subdomain }) client.close(); // 操作完成后关闭连接,避免资源泄漏 }) .catch(err => { console.error('MongoDB连接失败:', err); return NextResponse.error(); }); } export const config = { matcher: '/(.*)', }
2. 改用Edge兼容的MongoDB访问方案
若修复语法后仍报错,推荐使用以下两种适配Edge环境的方案:
方案一:使用MongoDB Atlas Data API
通过HTTP请求调用Data API,完全兼容Edge环境,无需安装官方驱动:export async function middleware(req: NextRequest) { const host = req.headers.get('host'); const subdomain = getValidSubdomain(host); if(!subdomain) return NextResponse.next() try { const response = await fetch('https://<你的集群ID>.mongodb-data-api.mongodb-app.com/api/v1/action/findOne', { method: 'POST', headers: { 'Content-Type': 'application/json', 'api-key': process.env.MONGODB_DATA_API_KEY }, body: JSON.stringify({ dataSource: '<数据源名称>', database: '<数据库名>', collection: '<集合名>', filter: { name: subdomain } }) }); const data = await response.json(); if(data.document) { // 子域名存在,继续请求流程 return NextResponse.next(); } else { // 子域名不存在,返回404或跳转 return NextResponse.redirect(new URL('/404', req.url)); } } catch(err) { console.error('查询子域名失败:', err); return NextResponse.error(); } }方案二:使用Edge兼容驱动包
尝试使用mongodb-edge-client这类第三方兼容包,或升级至最新版mongodb驱动(部分版本已优化Edge兼容性),需根据你的Next.js版本测试适配情况。
3. 强制使用Node.js运行时(不推荐)
若必须使用官方驱动,可强制让中间件运行在Node.js Runtime,但会丧失Edge环境的性能优势。修改next.config.js:
module.exports = { experimental: { runtime: 'nodejs', // 强制切换为Node.js运行时 }, }
内容的提问来源于stack exchange,提问作者Arturo Verbel De León
相关产品推荐
相关产品推荐

