如何在Morgan自定义异步日志函数中正确返回值?
问题解决:Morgan中使用async函数返回"[object Promise]"的处理方案
问题根源
Morgan的自定义格式函数要求同步返回字符串,而async函数默认返回Promise对象,当Morgan尝试将这个Promise转为字符串时,就会输出"[object Promise]"。不能直接在format函数中使用async/await,因为Morgan不支持处理异步返回值。
解决方案1:异步逻辑与格式返回分离(IIFE方式)
保持format函数为同步,内部用立即执行异步函数(IIFE)处理日志存储,不阻塞Morgan的格式输出:
const log = require("./queries/logQuery"); const moment = require('moment'); const morgan = require('morgan'); const custom = (tokens, req, res) => { if(req.session){ // 用IIFE执行异步日志存储,不影响Morgan的同步返回 (async () => { const date = moment().locale('id').format('DD-MM-YYYY HH:mm:ss'); const usr = req.session.superadmin || req.session.user; const method = tokens.method(req, res); const endpoint = tokens.url(req, res); const statusCode = tokens.status(req, res); try { await log.addLog(date, usr, method, endpoint, statusCode); } catch (err) { console.error('日志存储失败:', err); } })(); return [ tokens.method(req, res), tokens.url(req, res), tokens.status(req, res), tokens.res(req, res, 'content-length'), '-', tokens['response-time'](req, res), 'ms' ].join(' ') } } router.use(morgan(custom))
解决方案2:拆分中间件(更清晰的架构)
单独写一个中间件处理异步日志存储,Morgan只负责同步输出格式:
const log = require("./queries/logQuery"); const moment = require('moment'); const morgan = require('morgan'); // 异步日志存储中间件:监听响应完成事件 router.use((req, res, next) => { res.on('finish', async () => { if(req.session){ const date = moment().locale('id').format('DD-MM-YYYY HH:mm:ss'); const usr = req.session.superadmin || req.session.user; const method = req.method; const endpoint = req.originalUrl; const statusCode = res.statusCode; try { await log.addLog(date, usr, method, endpoint, statusCode); } catch (err) { console.error('日志存储失败:', err); } } }); next(); }); // Morgan仅处理日志格式输出 router.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
关键说明
- 两种方案都避免了让Morgan的format函数返回Promise,彻底解决
[object Promise]问题 - 异步操作需添加错误捕获,避免出现未处理的Promise拒绝报错
内容的提问来源于stack exchange,提问作者ipeenk downloader
相关产品推荐
相关产品推荐

