Express 4.x中如何await封装的sqlite3异步查询函数返回结果
问题核心原因
- 原
getPerson函数内的return语句写在db.get的回调函数中,返回值只会被sqlite3内部接收,不会作为getPerson的外层返回值,直接调用永远会得到undefined - sqlite3 5.x默认采用回调风格API,没有返回Promise结构,无法直接被
await关键字等待 - Express 4.x 不会自动捕获async路由函数中抛出的异常,未做处理时出错会导致请求挂起,无法正常返回响应
具体实现方案
第一步:将回调风格的数据库方法包装为Promise
要使用async/await,必须让异步函数返回Promise对象,同时修正原代码的SQL注入风险:
// 传入已初始化的sqlite3实例db function getPerson(id) { return new Promise((resolve, reject) => { // 使用?占位符做参数化查询,避免SQL注入,禁止直接拼接字符串到SQL语句中 db.get('SELECT * FROM People WHERE id = ?', [id], (error, row) => { if (error) { // 查询出错时抛出异常 return reject(error) } if (!row) { // 未查询到对应数据时返回false,对齐原有逻辑 return resolve(false) } // 查询成功返回人员姓名 resolve(row.name) }) }) }
第二步:在Express 4.x路由中调用
Express 4.x 支持async函数作为路由回调,只是需要手动处理异常,有两种常用写法:
写法1:单路由内直接捕获异常
适合路由数量少的场景,不需要额外封装:
// 路由回调添加async关键字,内部即可使用await app.get('/person/:id', async (req, res) => { try { // 等待异步查询完成,拿到最终结果 const person = await getPerson(req.params.id) if (person) { return res.status(200).send(person) } res.sendStatus(400) } catch (err) { // 捕获数据库错误等异常,避免请求挂死 console.error('查询人员信息失败:', err) res.sendStatus(500) } })
写法2:封装通用异步路由处理函数
适合项目路由较多的场景,避免每个路由重复写try/catch:
// 通用异步包装器,自动捕获async函数抛出的异常传给错误处理中间件 const asyncRoute = handler => (req, res, next) => { Promise.resolve(handler(req, res, next)).catch(next) } // 用包装器包裹路由回调 app.get('/person/:id', asyncRoute(async (req, res) => { const person = await getPerson(req.params.id) if (person) { return res.status(200).send(person) } res.sendStatus(400) })) // 挂载全局错误处理中间件,统一处理所有路由抛出的异常 app.use((err, req, res, next) => { console.error('服务异常:', err) res.sendStatus(500) })
注意:原代码中通过字符串拼接生成SQL语句的写法存在严重SQL注入漏洞,必须替换为参数化查询写法,sqlite3会自动对传入的参数做转义处理,彻底避免注入风险。
内容的提问来源于stack exchange,提问作者bagatov
相关产品推荐
相关产品推荐

