Node.js使用aws-sdk SNS错误无法捕获及Mongoose事务异常问题
问题根因
- 错误无法被
catch捕获:sns.publish使用回调模式编写,回调为异步执行,触发时外层try/catch上下文已经销毁,抛出的错误无法被捕获,直接变为未捕获异常导致程序崩溃。 MongoTransactionError报错:代码没有等待sns.publish的执行结果就直接执行finally块的session1.endSession(),事务被提前终止,等回调触发调用commitTransaction时,事务已经处于结束/中止状态,因此抛出状态冲突错误。
修复方案
将sns.publish改为Promise调用形式,配合await等待执行结果,所有异步错误都可以被外层try/catch捕获,同时保证事务状态流转顺序正确。
修复后代码
// 依赖引入等逻辑保留在上方 const verifyPhone = async (req, res) => { const { phoneNumber } = req.body; const { userId } = req.user; let code = generateCode(6); const session1 = await mongoose.startSession(); try { session1.startTransaction(); const newCode = await PhoneCode.create( [ { userId, code, }, ], { session: session1 } ); // 改为Promise形式调用sns.publish,用await等待执行结果 const result = await sns.publish({ MessageAttributes: { "AWS.SNS.SMS.SenderID": { DataType: "String", StringValue: "Testing", }, "AWS.SNS.SMS.SMSType": { DataType: "String", StringValue: "Promotional", }, }, Message: "Your code: " + code, PhoneNumber: phoneNumber, // 替换原有硬编码的测试号码 }).promise(); // 短信发送成功后再提交事务 await session1.commitTransaction(); console.log("transaction committed"); return res.status(200).json({ message: "SMS sent", result }); } catch (e) { // 所有报错统一在此处处理,中止事务 await session1.abortTransaction(); return res.status(500).json({ message: "Something went wrong!", error: e }); } finally { // 事务处理完成后再关闭会话 await session1.endSession(); } }; module.exports = verifyPhone;
核心修改说明
- 调用
sns.publish后追加.promise()将回调方法转为Promise形式,使用await等待执行结果后,SNS抛出的所有错误(比如手机号格式错误、权限不足等)都能被外层try/catch正常捕获,不会出现未捕获异常。 - 所有事务操作(
commitTransaction、abortTransaction、endSession)都添加await,确保异步操作执行完成再进入下一步流程。 - 流程调整为:SNS发送成功才提交事务,任意环节报错直接中止事务返回错误响应,完全避免事务状态冲突的问题。
内容的提问来源于stack exchange,提问作者Nez Nez
相关产品推荐
相关产品推荐

