Web服务中return语句的作用及前端接收return 'OK'的方法
问题解答
1. 代码里return 'OK'的实际作用
你的路由处理函数是async类型,在Express里有明确规则:
- 如果函数内没有调用
res.send()/res.end()这类发送响应的方法,Express会自动把return的值当成响应发给前端——字符串直接发送,对象会转成JSON格式。 - 但你的代码里,
getTIFFForSubsetAsNIRRange的回调中已经调用了res.send(),而且这个回调是异步执行的。也就是说,return 'OK'会先同步执行,Express会先尝试把'OK'发出去;等后面回调触发再调用res.send()时,就会触发Cannot set headers after they are sent to the client错误——因为响应已经被发送过一次了。
说白了,你当前代码里的return 'OK'不仅没用,还会埋下报错隐患,属于重复发送响应的问题。
另外提一句:你代码里getTIFFForSubsetAsNIRRange同时用了回调和.then()/.catch(),这是典型的异步模式混用错误。如果这个方法返回Promise,就不用传回调;如果它是回调式的,就不能用.then(),这种混用会让逻辑顺序彻底乱掉。
2. 怎么让前端收到'OK'
有两种靠谱的实现方式:
方式一:直接用res.send()发送
把回调里的响应内容改成'OK'即可,或者在合适时机调用res.send('OK')。比如如果getTIFFForSubsetAsNIRRange执行成功后要返回'OK',可以改用await的形式(前提是这个方法返回Promise,去掉回调参数):
app.post('/getTIFFForSubsetAsNIRRange/', async (req, res, next) => { // 保留原有参数校验代码 if (req == undefined) throw new Error('req is undefined, has value:' + req) if (!req.body) throw new Error('req.body is undefined, has value:' + req.body) if (!req.body.wktRepr) throw new Error('req.body.wktRepr is undefined or not exist. Please check the key/value of the json object sent from the front-end. req.body.wktRepr:' + req.body.wktRepr) if (!req.body.epsgCode) throw new Error('req.body.epsgCode is undefined or not exist. Please check the key/value of the json object sent from the front-end. req.body.epsgCode:', + req.body.epsgCode) const wktRepr = req.body.wktRepr const epsgCode = req.body.epsgCode console.info(infoTag, 'posted body to /getTIFFForSubsetAsNIRRange/ contains::' + 'wktRepr:', wktRepr) console.info(infoTag, 'posted body to /getTIFFForSubsetAsNIRRange/ contains::' + 'epsgCode:', epsgCode) const wktInEPSG32632 = transformWKT(epsgCode, sysResources.CONST_EPSG_32632, wktRepr) try { // 用await替代回调和.then()链式调用 const contents = await getTIFFForSubsetAsNIRRange( '2019-10-05', 'S2_GermanyGrid', wktInEPSG32632, credentials.RASDAMAN_LOGIN_USER_NAME, credentials.RASDAMAN_LOGIN_PASSWORD ) console.info(infoTag, '/getTIFFForSubsetAsNIRRange/::content', contents) // 直接发送'OK'给前端 res.send('OK') console.info({msg: infoTag + 'WS /getTIFFForSubsetAsNIRRange/ succeeded.'}) } catch (e) { console.error({msg: new Error(errorTag + 'WS /getTIFFForSubsetAsNIRRange/ failed.'), error: e}) // 错误时返回500状态码和提示 res.status(500).send('请求失败') } })
方式二:利用async函数的返回值(不调用res.send)
如果不想手动调用res.send(),可以直接return 'OK',但必须保证全程不调用任何res.send()/res.end()方法,Express会自动把这个返回值作为响应发送:
app.post('/getTIFFForSubsetAsNIRRange/', async (req, res, next) => { // 保留原有参数校验代码 if (req == undefined) throw new Error('req is undefined, has value:' + req) if (!req.body) throw new Error('req.body is undefined, has value:' + req.body) if (!req.body.wktRepr) throw new Error('req.body.wktRepr is undefined or not exist. Please check the key/value of the json object sent from the front-end. req.body.wktRepr:' + req.body.wktRepr) if (!req.body.epsgCode) throw new Error('req.body.epsgCode is undefined or not exist. Please check the key/value of the json object sent from the front-end. req.body.epsgCode:', + req.body.epsgCode) const wktRepr = req.body.wktRepr const epsgCode = req.body.epsgCode console.info(infoTag, 'posted body to /getTIFFForSubsetAsNIRRange/ contains::' + 'wktRepr:', wktRepr) console.info(infoTag, 'posted body to /getTIFFForSubsetAsNIRRange/ contains::' + 'epsgCode:', epsgCode) const wktInEPSG32632 = transformWKT(epsgCode, sysResources.CONST_EPSG_32632, wktRepr) try { await getTIFFForSubsetAsNIRRange( '2019-10-05', 'S2_GermanyGrid', wktInEPSG32632, credentials.RASDAMAN_LOGIN_USER_NAME, credentials.RASDAMAN_LOGIN_PASSWORD ) console.info(infoTag + 'WS /getTIFFForSubsetAsNIRRange/ succeeded.') // Express自动把这个'OK'发送给前端 return 'OK' } catch (e) { console.error({msg: new Error(errorTag + 'WS /getTIFFForSubsetAsNIRRange/ failed.'), error: e}) // 错误场景还是要调用res.status()设置状态码 res.status(500).send('请求失败') } })
额外提醒
- 别混用回调和Promise:
getTIFFForSubsetAsNIRRange要么用回调,要么用Promise,同时用两者只会让逻辑混乱,容易出bug。 - async函数里尽量用
await代替.then()/.catch(),代码可读性会高很多。
内容的提问来源于stack exchange,提问作者Amrmsmb
相关产品推荐
相关产品推荐

