axios-关于封装一个底层axios请求和拦截器interceptors,catch错误(throw或reject)?
错误代码
axios+拦截器+自定义请求头处理+自定义请求头导致的请求预检处理
axios-统一用拦截器在header请求头和请求体中添加参数并使用PHP获取
axios-关于封装一个底层axios请求和拦截器interceptors,catch错误(throw或reject)?
axios-options请求预检和Vue中axios封装以及withCredentialstrue
axios-abortController、signal配合axios实现一个可以中断请求的操作
axios.interceptors.response.use(
// 在 Axios 的响应拦截器中,成功拦截器必须返回 response(或修改后的 response),否则后续的 .then 会接收到 undefined。
async (response) => {
// 这里必须返回response,否则后续.then会拿到undefined
// return response;
},
async (error) => {
// console.log(error.code)
// 统一处理比如超时等错误
switch (error.code) {
// 超时错误
case 'ECONNABORTED':
...
break;
// 网络错误(比如跨域等)
case 'ERR_NETWORK':
...
break;
// 主动中断请求
case 'ERR_CANCELED':
console.log('主动中断请求', error.code);
break;
default:
// 处理其他网络错误
...
}
return Promise.reject(error);
}
);上面是一个响应的拦截器,当有数据响应返回的时候,都会使用拦截器进行处理,所以可以在拦截器中,对错误进行统一的处理。
注意:成功的拦截器必须返回,否则前端就算请求成功,接受到的数据也是undefined
async (response) => {
// 这里必须返回response,否则后续.then会拿到undefined
return response;
},然后基于axios封装上传的方法:
export function upload(url, formData) {
// 校验参数:确保传递的是FormData(避免传错格式)
if (!(formData instanceof FormData)) {
console.error('upload方法仅支持FormData参数!');
throw new Error('参数格式错误,需传递FormData');
// return Promise.reject(new Error('参数格式错误,需传递FormData'));
}
// 独立请求配置:覆盖默认头,确保文件格式正确
const requestConfig = {
headers: {
// 关键:设置为multipart/form-data(axios也会自动识别FormData并生成,这里显式设置更保险)
'Content-Type': 'multipart/form-data'
}
};
// 发送文件上传请求
return axios.post(url, formData, requestConfig).then((res) => {
// 标记 ①
const serverData = res.data;
// console.log(serverData)
if (serverData.code === ERR_OK) {
return serverData.data; // 返回后端的文件URL等数据
} else {
errorHandle(serverData);
console.log('文件上传失败:', serverData);
throw new Error(serverData.msg || '接口请求失败');
}
}).catch((e) => {
// 标记②
// 重点 一会注重讨论这里!!!!
console.log('图片上传失败:', e);
throw new Error('图片上传失败,请稍候重试');
// return Promise.reject(new Error('Something went wrong'));
// return null;
});
}对底层方法再封装
export function uploadImage(imagefile) {
return upload(
SERVICE.upload_image,
imagefile
);
}在其他组件中调用:
const formData = new FormData();
formData.append('image', file); // 表单字段名与后端保持一致
// 调用上传接口
uploadImage(formData)
.then(response => {
if (response) {
// 标记③
...
} else {
// 标记④
throw new Error('图片上传失败,请稍候重试');
}
})
.catch((err) => {
// 标记⑤
alert(err.message)
})
.finally(() => {
...
});因为我在响应拦截器中,没有返回response(注释掉了),所以导致了upload里面的then((res))返回的是undefined,导致执行顺序就是:标记② -> 标记⑤
catch中应该怎么写
核心结论
在你当前的upload函数中,throw new Error(...)和return Promise.reject(...)在功能上是等价的,都能正确地将 Promise 状态变为 rejected,并将错误传递给下一个.catch()或try/catch块。
return null
.catch((e) => {
console.log('图片上传失败:', e);
return null;
});return null 本质:成功态(resolved)会进入 await 的 “成功结果”,response 直接等于 null,用 if(!response) 判断失败即可。
async function xxx() {
const result = await uploadImage(formdata)
if(!result) {
是null 代表失败,必须与后端确认,不会返回null,用null来代表失败的状态
}
}Promise.reject(null) 失败态(rejected) 会直接触发 catch(或 try/catch 的 catch 块),无法通过 response 拿到 null。
throw new Error(推荐)
当在一个 Promise 的.then()或.catch()回调函数内部使用throw时,它会自动捕获这个错误,并将当前的 Promise 链状态变为rejected,然后将Error对象作为拒绝原因(reason)传递下去。
工作流程:
somePromise.then(result => {
// 发生错误
throw new Error('Something went wrong');
}).catch(error => {
// error 就是上面抛出的 Error 对象
console.log(error.message); // 输出: "Something went wrong"
});标准做法:这是在 Promise 链中触发错误的标准和推荐方式。
自动包装:
throw会自动将你抛出的任何东西(无论是Error对象还是字符串)包装成一个被拒绝的 Promise。不过,强烈建议总是抛出Error对象,因为它包含了堆栈跟踪(stack trace),这对于调试至关重要。
return Promise.reject
这是一种更显式的方式来拒绝一个 Promise。它直接返回一个状态为 rejected 的新 Promise 对象,并将你提供的参数作为拒绝原因(可以接受任何参数,布尔型、字符串等等)。
somePromise.then(result => {
// 显式返回一个被拒绝的 Promise
return Promise.reject(new Error('Something went wrong'));
}).catch(error => {
// error 就是传递给 Promise.reject 的 Error 对象
console.log(error.message); // 输出: "Something went wrong"
});注意!如果处理端(标记⑤)获取错误信息方法是:
.catch((err) => {
// 标记⑤
alert(err.message)
})
那么对应的抛错写法是:return Promise.reject(new Error('Something went wrong'));
传递给Promise.reject 的是一个 Error 对象而如果处理端(标记⑤) 获取错误方法是:
.catch((errmsg) => {
// 标记⑤
alert(errmsg)
})
那么对应的抛错写法是:return Promise.reject('Something went wrong');错误用法,底层方法:
.catch((e) => {
console.log('图片上传失败:', e);
// 错误:传递了一个字符串,而不是 Error 对象
return Promise.reject('图片上传失败,请稍候重试');
});在这种情况下,catch块接收到的err就是这个字符串'图片上传失败,请稍候重试'。当你尝试访问err.message时,因为字符串没有message属性,所以会得到undefined。
正确用法:
.catch((e) => {
console.log('图片上传失败:', e);
// 正确:传递一个 Error 对象
return Promise.reject(new Error('图片上传失败,请稍候重试'));
});或者,更简单的,直接throw:
.catch((e) => {
console.log('图片上传失败:', e);
// 更简洁,效果相同
throw new Error('图片上传失败,请稍候重试');
});所以,最终我推荐使用throw,更简洁和直观。并且在 Promise 链中是标准做法。
最终修改
export function upload(url, formData) {
if (!(formData instanceof FormData)) {
// 使用 throw 抛出参数错误
console.error('upload方法仅支持FormData参数!');
throw new Error('参数格式错误,需传递FormData');
}
const requestConfig = {
headers: {
'Content-Type': 'multipart/form-data'
}
};
// 注意:因为我们在外面加了 async,所以这里可以直接 return axios.post(...)
return axios.post(url, formData, requestConfig).then((res) => {
const serverData = res.data;
if (serverData.code === ERR_OK) {
return serverData.data;
} else {
errorHandle(serverData);
console.log('文件上传失败:', serverData);
// 后端返回业务错误,使用 throw
throw new Error(serverData.msg || '接口请求失败');
}
}).catch((e) => {
console.log('图片上传失败:', e);
// 捕获网络错误或前面抛出的所有错误,统一处理后再次抛出
// 这样可以在最终的 catch 中获取到这个统一的错误信息
throw new Error(e.message);
});
}最终结论就是
throw new Error 或者 return Promise.reject( new Error('message') )
目录