axios-关于封装一个底层axios请求和拦截器interceptors,catch错误(throw或reject)?

627次阅读 11人点赞 作者: WuBin 发布时间: 2025-11-13 11:20:28
扫码到手机查看

错误代码

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') )
点赞 支持一下 觉得不错?客官您就稍微鼓励一下吧!
关键词:拦截器,interceptors,axios,throw,promise,reject
推荐阅读
  • python基础-操作列表和迭代器

    python基础笔记-操作列表和迭代器的相关方法

    6708次阅读 164人点赞 发布时间: 2024-06-13 13:26:27 立即查看
  • uniapp实现被浏览器唤起的功能

    当用户打开h5链接时候,点击打开app若用户在已经安装过app的情况下直接打开app,若未安装过跳到应用市场下载安装这个功能在实现上主要分为两种场景,从普通浏览器唤醒以及从微信唤醒。

    12221次阅读 828人点赞 发布时间: 2022-12-14 16:34:53 立即查看
  • PHP

    【正则】一些常用的正则表达式总结

    在日常开发中,正则表达式是非常有用的,正则表达式在每个语言中都是可以使用的,他就跟JSON一样,是通用的。了解一些常用的正则表达式,能大大提高你的工作效率。

    15425次阅读 646人点赞 发布时间: 2021-10-09 15:58:58 立即查看
  • 【中文】免费可商用字体下载与考证

    65款免费、可商用、无任何限制中文字体打包下载,这些字体都是经过长期验证,经得住市场考验的,让您规避被无良厂商起诉的风险。

    16367次阅读 1304人点赞 发布时间: 2021-07-05 15:28:45 立即查看
  • Vue

    Vue3开发一个v-loading的自定义指令

    在vue3中实现一个自定义的指令,有助于我们简化开发,简化复用,通过一个指令的调用即可实现一些可高度复用的交互。

    18720次阅读 1503人点赞 发布时间: 2021-07-02 15:58:35 立即查看
  • JS

    关于手机上滚动穿透问题的解决

    当页面出现浮层的时候,滑动浮层的内容,正常情况下预期应该是浮层下边的内容不会滚动;然而事实并非如此。在PC上使用css即可解决,但是在手机端,情况就变的比较复杂,就需要禁止触摸事件才可以。

    16901次阅读 1366人点赞 发布时间: 2021-05-31 09:25:50 立即查看
  • Vue

    Vue+html2canvas截图空白的问题

    在使用vue做信网单页专题时,有海报生成的功能,这里推荐2个插件:一个是html2canvas,构造好DOM然后转canvas进行截图;另外使用vue-canvas-poster(这个截止到2021年3月...

    32715次阅读 2567人点赞 发布时间: 2021-03-02 09:04:51 立即查看
  • Vue

    vue-router4过度动画无效解决方案

    在初次使用vue3+vue-router4时候,先后遇到了过度动画transition进入和退出分别无效的情况,搜遍百度没没找到合适解决方法,包括vue-route4有一些API都进行了变化,以前的一些操...

    28566次阅读 2199人点赞 发布时间: 2021-02-23 13:37:20 立即查看
交流 收藏 目录