Next.js中tRPC调用node-imap获取邮箱OTP的异常问题
Next.js + tRPC + node-imap 提取OTP的问题解决
问题1:调用trpc.getOtp.useQuery()返回空数组
原因
遍历邮件时使用了mailParser.simpleParser的回调版本,但未等待所有解析完成就执行了await imap.end(),读取全局OTPcodes数组时解析还没完成,导致返回空数组。
解决方案
将mailParser.simpleParser封装为Promise形式,用Promise.all等待所有邮件解析完成,同时把OTPcodes移到run函数内部,避免全局变量污染。
问题2:run()自动重复执行/调用process.exit()出现ECONNRESET
原因
- 全局变量
OTPcodes不会重置,每次请求都会累加数据,且Next.js开发模式下的热重载可能触发重复执行。 process.exit()会直接终止Node.js进程,此时imap连接未正常关闭,导致抛出ECONNRESET错误。
解决方案
- 放弃全局变量存储OTP,将数组放到
run函数内部,每次请求重新生成。 - 移除
process.exit(),确保所有异步操作完成后再正常关闭imap连接。
修改后的完整代码
async function run() { // 把OTPcodes移到函数内部,避免全局污染 const OTPcodes: (string | null)[] = []; const config = { imap: { user: process.env.NEXT_PUBLIC_YMAIL_USER, password: process.env.NEXT_PUBLIC_YMAIL_PASSWORD, host: process.env.NEXT_PUBLIC_YMAIL_HOST, port: process.env.NEXT_PUBLIC_EMAIL_PORT, tls: process.env.NEXT_PUBLIC_EMAIL_TLS, }, debug: logger.info.bind(logger), }; const imap = new MyImap(config); const result = await imap.connect(); logger.info(`result: ${result}`); const boxName = await imap.openBox(); logger.info(`boxName: ${boxName}`); const criteria = [['HEADER', 'SUBJECT', ' Account']]; const emails = await imap.fetchEmails(criteria); // 把simpleParser封装成Promise,用Promise.all等待所有解析完成 await Promise.all(emails.map(async (email) => { const parsed = await new Promise((resolve, reject) => { mailParser.simpleParser(email.body, (err, parsed) => { if (err) reject(err); else resolve(parsed); }); }); const otp = matchOTP(parsed.text); console.log("OTP "+ otp); if (otp) OTPcodes.push(otp); })); await imap.end(); return OTPcodes; // 直接返回结果,不用全局变量 } function matchOTP(email: string){ const regex = /\b(?![A-Z]{5}\b)[A-Z0-9]{5}\b/; const match = email.match(regex); return match && match[0]; } async function parseEmails(){ try { return await run(); // 直接返回run的结果 } catch (error) { logger.error(error); throw error; // 抛出错误让tRPC处理,不要终止进程 } } const appRouter = router({ getOTP: publicProcedure.query(async () => { const otpCodes = await parseEmails(); console.log("Array of OTP "+JSON.stringify(otpCodes)); return otpCodes; }), }); export type AppRouter = typeof appRouter; export default trpcNext.createNextApiHandler({ router: appRouter, createContext: () => ({}), });
内容的提问来源于stack exchange,提问作者masu.mo
相关产品推荐
相关产品推荐

