如何从本地通过Node.js连接DocDB集群?解决connect-mongo适配问题
问题描述
我正尝试将MongoDB迁移至Amazon DocumentDB以实现统一管理,需在本地测试环境中基于Node.js + Express.js后端连接DocDB集群,但遇到诸多问题:
- AWS官方VPC外连接指引仅针对MongoDB Shell,对程序化连接帮助甚微;本地测试时
sslAllowInvalidHostnames参数用于避免localhost与证书域名不匹配错误,但使用connect-mongo会话管理包时启用该参数会触发MongoServerError: Authorization failure错误。 - 不使用
connect-mongo包时可正常连接DocDB,但该包是Express登录会话跟踪必需组件。 - 测试架构为:
localhost-frontend --- localhost-backend --- EC2 --- DocDB,端口转发已正常工作。 - 当前
connect-mongo配置(报错):
const MongoStore = require('connect-mongo'); var store; store = MongoStore.create({ mongoUrl: uri, dbName: 'server', collectionName: 'sessions', secret: ss, stringify: false, ttl: fifteen_min, mongoOptions: { tlsCAFile: process.env.TLSCAFILE, directConnection: true, tls: true, } });
直接用MongoClient可成功连接:
const client = new MongoClient(uri, { tlsCAFile: process.env.TLSCAFILE, //Specify the DocDB; cert tlsAllowInvalidCertificates: mode !== "prod", tlsAllowInvalidHostnames: mode !== "prod", directConnection: true, auth: { username: user, password: pass } }); client.connect().then((_) => console.log('Connection successful.'));
计划生产环境移除tslAllowInvalidHostnames,但本地测试阶段如何解决connect-mongo连接问题?是否有替代方案?
解决方案
修复connect-mongo连接问题
1. 补全MongoClient参数到connect-mongo配置
你当前的connect-mongo配置缺少本地测试必需的TLS参数,以及可能的授权参数(如果URI未包含账号密码)。修改后的配置如下:
const MongoStore = require('connect-mongo'); var store; store = MongoStore.create({ mongoUrl: uri, dbName: 'server', collectionName: 'sessions', secret: ss, stringify: false, ttl: fifteen_min, mongoOptions: { tlsCAFile: process.env.TLSCAFILE, directConnection: true, tls: true, // 加入本地测试需要的TLS兼容参数 tlsAllowInvalidCertificates: mode !== "prod", tlsAllowInvalidHostnames: mode !== "prod", // 如果URI里没包含账号密码,手动指定授权信息 auth: { username: user, password: pass } } });
注意:如果你的uri已经是mongodb://user:pass@host:port/格式,无需单独配置auth。
2. 排查授权失败根源
如果仍报授权错误,检查以下两点:
- 确认DocDB集群的账号密码正确,且该账号拥有
server数据库的读写权限。 - 验证EC2端口转发实例的安全组规则,确保允许EC2访问DocDB的27017端口。
替代方案
如果connect-mongo的问题暂时无法解决,可考虑以下临时方案:
1. 本地测试用内存存储会话
仅在本地测试阶段使用express-session的内存存储,无需依赖数据库:
const session = require('express-session'); app.use(session({ secret: ss, resave: false, saveUninitialized: false, cookie: { secure: mode === "prod" } }));
⚠️ 注意:内存存储不适合生产环境,服务重启后会话会全部丢失。
2. 基于MongoClient自定义会话存储
利用已能成功连接的MongoClient,手动实现符合express-session要求的存储适配器,核心是实现get、set、destroy方法:
const session = require('express-session'); const MongoClient = require('mongodb').MongoClient; class CustomMongoStore { constructor(client, dbName, collectionName, ttl) { this.collection = client.db(dbName).collection(collectionName); this.ttl = ttl; } async get(sid) { const doc = await this.collection.findOne({ _id: sid }); return doc ? doc.session : null; } async set(sid, session) { await this.collection.updateOne( { _id: sid }, { $set: { session, expires: new Date(Date.now() + this.ttl) } }, { upsert: true } ); } async destroy(sid) { await this.collection.deleteOne({ _id: sid }); } // 可选:更新会话过期时间的touch方法 async touch(sid, session) { await this.collection.updateOne( { _id: sid }, { $set: { expires: new Date(Date.now() + this.ttl) } } ); } } // 初始化客户端并挂载到express-session MongoClient.connect(uri, { tlsCAFile: process.env.TLSCAFILE, tlsAllowInvalidCertificates: mode !== "prod", tlsAllowInvalidHostnames: mode !== "prod", directConnection: true, auth: { username: user, password: pass } }).then(client => { const store = new CustomMongoStore(client, 'server', 'sessions', fifteen_min); app.use(session({ secret: ss, resave: false, saveUninitialized: false, store: store, cookie: { secure: mode === "prod" } })); });
内容的提问来源于stack exchange,提问作者S S
相关产品推荐
相关产品推荐

