文章目录
- 介绍
- 思路
- 实现
-
- [方法1.直接修改 umi-request](#方法1.直接修改 umi-request)
- [方法2.自定义 request 实例,通过 umi-request 库进行配置](#方法2.自定义 request 实例,通过 umi-request 库进行配置)
介绍
后端设计统一返回比如BaseResponse对象,前端也需要接收这个对象,从data取出想要的返回值。
前端请求比如之前返回的是number类型:
当返回参数类型变成BaseResponse,代码也需要更改:
很多请求方法都需要修改,一一修改不仅麻烦还可能容易漏改。因此我们同样可以整一个全局响应拦截器先来处理返回的BaseResponse,如果请求返回成功则取出data
返回,如果请求返回失败则直接抛出一个异常外部进行catch
,这样我们的请求仍然可以按照之前的写法无需更改。
思路
查看源码:request 里面的 RequestConfig 接口有 responseInterceptors 参数即响应拦截器,
这里创建了类型为 RequestConfig
的 config
变量,
然后根据 config
变量设置request
:
因此这里我们尝试在config
配置responseInterceptors
:
通过追溯源码定义 responseInterceptors
,
直接抄:发送请求打印响应
目测还算成功,起码拦截到了。但是有一个问题:我在源码里修改代码,而这个文件位于 .umi 目录,这个目录是框架生成的,每次重新启动项目这个文件就会恢复原样(相当于白改),因此我们不能在这儿改。
实现
方法1.直接修改 umi-request
直接在app.tsx
全局入口文件中,配置全局的request
,编写自己的响应处理逻辑。请求返回成功使用resolve
方法;请求返回失败使用reject
方法,外部方法用try catch
捕获,可参考上面的注册方法。
java
export const request: RequestConfig = {
baseURL: '/api',
timeout: 30000,
// 自定义全局响应拦截器
responseInterceptors: [
// @ts-ignore
function <T extends AxiosResponse<T, any> = any>(response: AxiosResponse<T>): WithPromise<AxiosResponse<T>> {
console.log('全局响应拦截器', response);
console.log('全局响应拦截器', response.data);
if (response.data.code === 0){
return Promise.resolve(response.data);
}
if (response.data.code === 40100) {
message.error('请先登录');
history.replace({
pathname: '/user/login',
search: stringify({
redirect: location.pathname,
}),
});
return Promise.reject(new Error('未登录'));
} else {
console.log('全局响应拦截器', response.data.description);
// @ts-ignore
return Promise.reject(new Error(response.data.description || '请求出错'));
}
}
]
};
注:这里返回响应的时候看着点,别返回错了!!!!!!!!!!!!!!!!
可参考下面的request
源码:
我们可以看到 request 最终返回的是一个 Promise
对象,使用 resolve
方法的时候返回的是 res.data
。
可配合请求打印响应拦截器的 response
输出日志:
最初的response
没有做任何处理响应状态码200。response.data
其实就是后端统一封装的返回对象比如BaseResponse。
=========================================================================================
因此这里自定义的全局响应拦截器返回的应该是response.data,而不是response.data.data,因为request最终返回的是Promise对象,返回的是上面的 res.data。简而言之就是人家帮我们取了一层 data 属性,我们返回他的上一级即可,不然取到的可能是undefined(别问我怎么知道的呜呜呜,不看源码一辈都不知道,后来想想也不难理解了,正常我们一般请求返回的响应直接拿到了结果,其实就是取的原始的response.data)。
//这里返回什么也不是绝对的,自定义拦截器的内部逻辑还是要看自己怎么设计的。
方法2.自定义 request 实例,通过 umi-request 库进行配置
java
import {extend, RequestMethod} from 'umi-request';
import {message} from "antd";
import {history} from "@@/core/history";
import {stringify} from "querystring";
/**
* 配置request请求时的默认参数
*/
const request: RequestMethod<true> = extend({
credentials: 'include', // 默认请求是否带上cookie
prefix: process.env.NODE_ENV === 'production' ? 'TODO' : 'http://localhost:8000/api',
});
/**
* 所有请求拦截器
*/
request.interceptors.request.use((url, options): any => {
console.log(`do request url = ${url}`)
return {
url,
options: {
...options,
headers: {},
},
};
});
/**
* 所有响应拦截器
*/
request.interceptors.response.use(async (response): Promise<any> => {
const res = await response.clone().json();
if (res.code === 0) {
return res.data;
}
if (res.code === 40100) {
history.replace({
pathname: '/user/login',
search: stringify({
redirect: location.pathname,
}),
});
message.error('未登录');
} else {
message.error(res.description);
}
return res;
});
export default request;
与方式1不同,这个直接返回res.data
即是我们要的data。
使用时比如api.tsx
文件的 request 依赖引入改成自定义的request
。