umi踩坑记录 —— useRequest 以及 umi 请求报错捕获流程
引言
我们的项目中使用了 useRequest 这个 hooks。今天下午我在写项目的过程中发现,假如我的登录密码是错误的,当后端成功返回异常信息后,页面就报错了,提示我异常没有被成功捕获(Unhandled Rejection)......因为这个问题折腾了好几个小时
原因
先说一下原因吧,因为目前 Umi 4 中内置的 ahooks 版本为 2.x 版本,2.x 版本中的 useRequest 并没有返回 runAsync,即异步请求函数。但是在某些场景中,我希望通过异步请求来实现某些功能,又不想在项目中使用两种请求方案,即 useRequest 和直接使用 services 封装的请求函数
于是,我安装了 ahooks 3.x。在需要使用异步请求的地方,引用了 ahooks 3.x 中的 useRequest 函数,登录请求便在其中~
解决方案
解决方案为:为登录请求相关的 useRequest 及所有异步请求的函数都加了 try ... catch
总结
runAsync 返回的异步函数中,想要捕获错误使用自带的 onError 函数和 errorHandle 函数是处理不了的,如果该异步函数抛出了异常,上述的函数再处理完成后还会抛给外部一个异常,所以最后的解决方法必须要在最外层加一个 try ... catch
既然谈到这里了,也都走了一遍坑,我就总结一下 umi 全局请求是怎么捕获错误的
umi 全局请求的错误是怎么捕获的
在 umi 项目中,我们优先使用 umi 插件自带的 request,首先需要在 .umirc.ts 文件中增加配置
export default defineConfig({
request: {},
});
在定义请求时,引用 umi 中的请求,我使用的是 umi/max
import { BASE_URL } from './config.ts';
import { request } from '@umijs/max';
export const requestUserLogin = async (data: any) => {
return await request(`${BASE_URL}/api/user/login`, {
method: 'post',
data,
});
}
我们通常需要对后端传回的数据进行全局处理,比如后端虽然成功响应,但是在返回的 data 中 code 不为 200 或者 success,我们就需要在 app.tsx 中进行配置
// app.tsx
import type { RequestConfig } from '@umijs/max';
export const request: RequestConfig {
timeout: 1000 * 6,
errorConfig: {
errorThrower: (res) => {
// 后端返回数据后,都会执行此函数,如果不符合条件,我们可以手动抛出一些错误,从而会被 errorHandle 捕获
// 此处的 res 为响应拦截器中的 res.data 部分,为后端自己手动封装的 body 部分
const { code, message } = res;
if (code !== 200) {
const error: any = new Error(message);
error.name = 'BizError';
error.info = { message, code };
throw error; // 抛出自制的错误
},
},
// 此函数只能对 useRequest 中 run 返回的同步函数内部的异步函数进行错误捕获;如果为 runAsync 或者我们自定义的异步请求函数,并且该错误是由 errorThrower、 responseInterceptors 或者 requestInterceptors 抛出(即不是请求的 status 不为 200),在 errorHandle 执行完之后还会抛出一个错误,所以异步请求一定要记得加 try ... catch
errorHandle: (error) => {
// 分情况处理错误
// 错误可能为我们手动抛出的错误,可能为状态码(status)不为 200 的错误,或者后端服务没有响应的错误,或者是发送请求时出现的其它错误等等
if (error.name === 'BizError') {
// switch ...
} else if (error.response?.status) {
// 请求已发送,并且收到了响应,但是状态码超出了 2xx 的范围
// 分情况处理
// switch (error.response.status) {}
} else if (error.request) {
// 请求已发送,但是没有收到响应
} else {
// 发送请求前出现了问题
}
}
},
// 请求拦截
requestInterceptors: () => {},
// 响应拦截
responseInterceptors: (res) => {
// 此处抛出的错误会直接进入errorHandle,但我们一般选择在errorThrower中抛出
// 此处的 res 包含整个响应内容,包括headers、status、data、config等等
return res;
}
}
转载自:https://juejin.cn/post/7353536741615616011