如何在async异步函数中正确处理res.status(<code>).send()响应?
async场景下HTTP响应处理正确写法说明
三种示例写法的问题逐一分析
randomFunction3完全错误
当触发req.body.automaticFail判断分支时,执行res.status(500).send()后没有终止函数执行,代码会继续向下运行,再次调用res.status(200).send(),触发Node.js经典报错Cannot set headers after they are sent to the client,绝对不可用。randomFunction冗余且存在隐患res.send()执行后已经完成了对客户端的响应返回,后续的return Promise.reject()/Promise.resolve()完全多余。在云函数场景下,返回Promise.reject()会被平台判定为函数执行失败,即使你已经给客户端返回了正常的业务响应,也会产生不必要的错误日志和告警。randomFunction2可正常运行,接近最优写法
该写法通过return终止了后续代码执行,不会触发二次响应问题,唯一可以优化的点是不需要显式返回res对象,直接return终止函数执行即可,当然保留返回res的写法也不会引发运行错误。
最优实现方案
Node.js HTTP处理逻辑中,只要调用res.send()/res.json()/res.end()这类方法,就已经完成了响应报文的发送,仅需要保证调用后终止函数执行,避免后续再操作响应对象即可。
正确写法示例:
export const correctFunction = functions.runWith(functionDefault).https.onRequest(async (req, res) => { functionSecurity.setHttpSecurityHeaders(res); if (req.body.automaticFail) { res.status(500).send(`This function automatically bombed out`); return; // 直接终止函数执行即可 } // 如有其他异步业务逻辑,必须加await等待执行完成 // const data = await db.collection('xxx').get() res.status(200).send(`This function automatically succeeded`); return; })
注意事项
- 所有涉及发送响应的分支,调用send类方法后必须加return终止执行,避免出现二次响应报错
- 不要在发送响应后返回Promise.reject,避免云函数平台误判执行失败
- 异步逻辑必须加await,否则会出现响应已经返回但业务逻辑还未执行完成的时序问题
内容的提问来源于stack exchange,提问作者Bobkitten
相关产品推荐
相关产品推荐

