如何在axios中设置两个互不干扰的拦截器,解决跨函数异常触发问题
问题原因
- axios 默认实例的拦截器是全局生效的,和你声明时所在的函数作用域没有关系,只要注册成功,所有经过该实例的请求/响应都会触发对应拦截器
- addUser 函数中存在低级错误:你注册的是 响应拦截器,卸载时调用的是
axios.interceptors.request.eject()(卸载请求拦截器的API),完全没有命中你要删除的响应拦截器,所以第一个拦截器会一直留在全局,后续所有响应都会触发它 - findUser 函数中注册的响应拦截器完全没有做卸载逻辑,也会一直全局生效
修复方案
方案1:快速修复现有拦截器逻辑
注意要把卸载逻辑放到 finally 块中,避免请求报错时走不到卸载代码:
async function addUser(user) { const config = { headers: { "Content-Type": "application/json", }, }; let interceptorResponse = null; try { interceptorResponse = axios.interceptors.response.use( (response) => { if (typeof response.data === "object") { let success = response.data.registerSuccess; let errors = response.data.errors; let data = response.data.data; let message = response.data.message; setData(() => { return { ...data, errors, registerSuccess: success, message }; }); } return response; } ); await axios.post("/users/register", user, config); } catch (err) {} finally { // 卸载对应的响应拦截器,且不管请求成功失败都执行 if (interceptorResponse !== null) { axios.interceptors.response.eject(interceptorResponse); } } } async function findUser(user) { const config = { headers: { "Content-Type": "application/json", }, }; let interceptorResponse = null; try { interceptorResponse = axios.interceptors.response.use((response) => { console.log(response); if (typeof response.data === "object") { let loginSuccess = response.data.data.loginSuccess; let message = response.data.message; console.log(response.data); setData(() => { return { ...data, loginSuccess, message }; }); } return response; }); await axios.post("/users/login", user, config); } catch (error) {} finally { if (interceptorResponse !== null) { axios.interceptors.response.eject(interceptorResponse); } } }
注意:这个方案只适合单请求串行的场景,如果存在并发请求,临时注册的全局拦截器依然可能错误处理其他请求的响应。
方案2(更推荐):去掉不必要的拦截器,直接处理请求返回结果
你的场景只是单个请求的响应处理,完全不需要用拦截器,直接处理axios.post返回的响应即可,不会有任何全局污染:
async function addUser(user) { const config = { headers: { "Content-Type": "application/json", }, }; try { const response = await axios.post("/users/register", user, config); if (typeof response.data === "object") { let success = response.data.registerSuccess; let errors = response.data.errors; let data = response.data.data; let message = response.data.message; setData(() => { return { ...data, errors, registerSuccess: success, message }; }); } } catch (err) {} } async function findUser(user) { const config = { headers: { "Content-Type": "application/json", }, }; try { const response = await axios.post("/users/login", user, config); console.log(response); if (typeof response.data === "object") { let loginSuccess = response.data.data.loginSuccess; let message = response.data.message; console.log(response.data); setData(() => { return { ...data, loginSuccess, message }; }); } } catch (error) {} }
如果确实有部分公共逻辑需要用拦截器,也可以用axios.create()为每个模块/场景创建独立的axios实例,不同实例的拦截器互相隔离,不会冲突。
内容的提问来源于stack exchange,提问作者Tamir Polyakov
相关产品推荐
相关产品推荐

