在Express控制器中调用axios时如何正确返回响应状态码
问题核心原因
你遇到的状态码始终为200的问题,根源有两个:
getAddressWithPostcode的catch块没有抛出错误,而是将错误信息包装成普通对象返回,导致该异步函数的Promise永远是resolved状态,永远走路由层的then分支,被硬设了200状态码- Express中
res.status()需要放在res.send()前调用,res.send()会直接结束响应,你原来写的res.send(data).status(200)里的status设置不会生效
现有写法的可优化点
你重构后的代码仍然存在几个隐患:
- 拼接地址时的
api-keey是笔误,会导致所有带门牌号的请求直接鉴权失败 - 成功请求返回的是
axios的响应体data,错误请求返回的是完整的response对象,数据结构不一致,若业务返回的data中恰好有status字段会触发逻辑异常 - 把错误结果放到
resolved分支处理,不符合Promise的设计逻辑,后续维护成本更高
最佳实践方案
1. 服务层只负责调用、不处理响应格式,错误直接抛出
const getAddressWithPostcode = async (params: Params) => { const { postCode, number } = params // 修复参数拼写笔误 const addressUrl = `${URL}/${postCode}${number ? `/${number}?api-key=${API_KEY}` : `?api-key=${API_KEY}`}` const { data } = await axios.get(addressUrl) return data }
这里不需要单独加try/catch,axios请求出错会自动抛出错误,进入Promise的rejected分支。
2. 路由层分别处理成功/错误分支,正确设置状态码
const findAddress = async (req: Request<Params>, res: Response, next: NextFunction) => { try { const data = await getAddressWithPostcode(req.params) // Express默认响应状态码为200,不需要额外设置 res.send(data) } catch (e) { // 优先取第三方服务返回的状态码,兜底设为500 const status = e.response?.status || 500 res.status(status).send({ service: 'Address service error', status, statusText: e.response?.statusText || 'Internal Server Error' }) } }
如果你的项目有全局错误处理中间件,也可以直接把错误传给next(e),在全局中间件统一做格式化返回,不用每个路由重复写错误逻辑:
// 全局错误处理中间件,放在所有路由之后注册 app.use((err, req, res, next) => { console.error(err) const status = err.response?.status || 500 res.status(status).json({ code: status, message: err.response?.statusText || err.message || '服务器内部错误' }) })
额外建议
如果需要区分是第三方服务错误还是你自己的服务错误,可以自定义错误类,抛出时带上错误类型,全局中间件根据错误类型返回不同的提示信息即可。
内容的提问来源于stack exchange,提问作者narliecholler
相关产品推荐
相关产品推荐

