fetch处理服务端响应及400状态码自定义错误实现方案
问题核心需求
- 成功响应场景:服务端返回2xx状态码无错误时,提取返回数据的指定字段,执行后续业务逻辑
- 错误响应场景:服务端返回400等错误状态码、携带自定义错误说明时,按状态码捕获错误,提取响应体中
data.error字段的错误文本,完成日志打印、DOM提示等操作
原有代码问题点
- DOM选择器错误:用户名输入框的jQuery选择器遗漏类名前缀
.,写为$('usernameCon input'),无法匹配到对应输入框元素 - Fetch状态判断逻辑完全错误:Fetch API 仅在网络故障、请求被中断等场景下会触发Promise reject进入catch,服务端返回400/500等HTTP错误状态时,Promise默认是成功状态,不会进入catch,因此原代码在catch中读取
error.responseStatus永远拿不到值 - Promise语法错误:
.then回调中直接跟if语句未包裹花括号,catch分支内错误嵌套无效箭头函数,不符合JS语法规范 - 后端接口响应写法错误:用户保存失败分支写为
res.send(400).send(err),Express中设置HTTP状态码必须调用res.status(code),原写法会导致状态码设置失效、响应格式异常
修正后代码
前端代码
$('.sign_upBtn').on('click', async function() { const name = $('.nameCon input').val() // 修正选择器,补上类名前缀. const username = $('.usernameCon input').val() const password = $('.passwordCon input').val() try { const res = await fetch('/api/user/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: name, username: username, password: password }) }) // 无论成功失败,先解析响应体JSON const respData = await res.json() // 手动判断HTTP状态码,非2xx状态统一抛错 if (!res.ok) { const err = new Error('request failed') err.status = res.status err.data = respData throw err } // 走到此处即为请求成功,执行正常业务逻辑 console.log('注册成功,返回用户数据:', respData) if (respData.name === 'john') { console.log(respData) // 其他自定义业务逻辑可写在此处 } } catch (error) { // 统一处理所有异常:网络错误、服务端返回的4xx/5xx错误 if (error.status === 400) { const errMsg = error.data?.error console.log('400错误信息:', errMsg) if (errMsg === 'username already exists') { // DOM操作示例:页面提示用户名已占用 $('.errTip').text('用户名已存在,请更换后重试') } } else { // 其他错误通用处理 console.log('请求异常:', error) $('.errTip').text('注册失败,请稍后重试') } } })
后端代码(Express)
router.post('/register', async(req, res) => { // 校验用户名是否已存在 const usernameExist = await User.findOne({ username: req.body.username }) if (usernameExist) { return res.status(400).send({ error: 'username already exists' }) } // 创建新用户 const user = new User({ name: req.body.name, phone_number: req.body.phone_number, username: req.body.username, password: req.body.password }) try { const savedUser = await user.save() // 创建成功返回201状态码更符合REST规范 res.status(201).send(savedUser) } catch (err) { // 修正状态码设置方式,统一错误响应格式 res.status(400).send({ error: err.message || '用户创建失败' }) } })
关键逻辑说明
- 禁止依赖catch分支捕获HTTP错误状态,必须在拿到Fetch返回的
Response对象后,第一时间通过res.ok(等价于状态码范围200-299)判断请求是否成功 - 非2xx状态的响应体必须正常通过
res.json()解析,否则无法拿到服务端返回的自定义错误信息 - 手动抛错时可以在Error对象上自定义挂载status、data属性,方便后续catch分支按状态码做差异化处理
内容的提问来源于stack exchange,提问作者seriously
相关产品推荐
相关产品推荐

