Axios作为前端领域常用的网络请求库,响应拦截器是处理接口返回数据的核心环节,不少开发者在编写拦截器逻辑时,会遇到拦截器执行后返回undefined的问题,导致后续请求处理流程出错。这个问题看似简单,实际涉及到拦截器的执行机制和返回值规则,需要针对性排查解决。
问题产生的常见原因
1. 拦截器未返回正确结果
Axios的响应拦截器本质上是一个处理函数,必须返回对应的结果才能让后续流程拿到数据。如果只做了数据修改却没有返回,就会直接返回undefined。
// 错误示例:未返回处理后的响应
axios.interceptors.response.use(
(response) => {
// 仅处理数据,没有返回
response.data = {
code: response.data.code,
result: response.data.data
};
},
(error) => {
return Promise.reject(error);
}
);
// 正确示例:返回处理后的响应
axios.interceptors.response.use(
(response) => {
response.data = {
code: response.data.code,
result: response.data.data
};
return response; // 必须返回响应对象
},
(error) => {
return Promise.reject(error);
}
);
2. 错误分支未正确返回Promise
响应拦截器的第二个参数是错误处理的回调,如果错误分支没有返回Promise.reject(error),而是直接抛出错误或者没有返回值,也会导致最终结果变成undefined。
// 错误示例:错误分支未返回Promise
axios.interceptors.response.use(
(response) => {
return response;
},
(error) => {
console.log('请求出错', error);
// 没有返回Promise.reject,导致后续拿不到错误结果
}
);
// 正确示例:错误分支返回Promise.reject
axios.interceptors.response.use(
(response) => {
return response;
},
(error) => {
console.log('请求出错', error);
return Promise.reject(error); // 必须返回被拒绝的Promise
}
);
3. 拦截器中抛出未捕获的异常
如果拦截器内部有同步代码抛出异常,且没有在内部捕获,也会导致整个拦截器执行中断,最终返回undefined。
// 错误示例:未捕获的异常
axios.interceptors.response.use(
(response) => {
// 假设response.data不存在,访问data属性会抛出异常
const data = response.data.xxx.yyy;
return response;
},
(error) => {
return Promise.reject(error);
}
);
// 正确示例:加入异常捕获
axios.interceptors.response.use(
(response) => {
try {
const data = response.data.xxx.yyy;
return response;
} catch (e) {
console.log('处理响应数据异常', e);
return response; // 或者根据需求返回默认数据
}
},
(error) => {
return Promise.reject(error);
}
);
问题排查步骤
- 第一步:检查响应拦截器的成功回调是否返回了响应对象或者处理后的数据,确保没有遗漏return语句。
- 第二步:检查错误回调是否返回了
Promise.reject(error),不要直接返回普通值或者不做返回处理。 - 第三步:在拦截器内部加入try-catch块,捕获可能存在的同步异常,避免执行流程中断。
- 第四步:在请求调用的then和catch中打印返回值,确认是拦截器返回的问题还是后续处理逻辑的问题。
规范的拦截器编写示例
以下是一个兼顾正常响应处理和错误处理的完整拦截器示例,可以直接参考使用:
import axios from 'axios';
const instance = axios.create({
baseURL: 'http://ipipp.com/api',
timeout: 5000
});
instance.interceptors.response.use(
// 成功响应处理
(response) => {
try {
// 统一处理响应数据格式
const { code, data, msg } = response.data;
if (code === 200) {
return data; // 直接返回需要的数据,后续请求直接拿data
} else {
// 业务错误处理
console.log('业务错误:', msg);
return Promise.reject(new Error(msg));
}
} catch (e) {
console.log('响应处理异常', e);
return Promise.reject(e);
}
},
// 错误响应处理
(error) => {
// 网络错误、超时等异常处理
if (error.response) {
console.log('接口状态码错误:', error.response.status);
} else if (error.request) {
console.log('无响应:', error.request);
} else {
console.log('请求配置错误:', error.message);
}
return Promise.reject(error);
}
);
// 调用示例
instance.get('/user/list')
.then((res) => {
console.log('获取到的数据:', res);
})
.catch((err) => {
console.log('请求失败:', err);
});
注意事项
如果拦截器中需要对响应做修改,要么返回修改后的完整响应对象,要么返回需要提取的数据部分,但是要保证后续请求处理的逻辑和返回值的格式匹配。如果返回的是普通数据而不是Promise,Axios会自动包装成Promise,但是如果没有返回任何值,就会直接返回undefined。另外,不要在拦截器中随意使用async/await却不处理返回值,async函数默认返回Promise,但是如果内部没有return,返回的Promise的resolve值会是undefined,同样会导致问题。