umi-request的使用相对比较简单, 甚至可以直接使用,由于其支持 typescript,再加上其使用简单,因此非常受大家的喜爱,下面就简单介绍下其使用方式吧
快速使用
下面就是最简单的使用方法,直接引入 request,直接使用即可
import request from "umi-request";
export function loginByInfos(
params: API.LoginParams,
options?: { [key: string]: any },
) {
//后面的泛型,表示返回数据 reponse 的数据类型,避免编译期间无法调用
return request<API.BaseResponse<any>>('/street_light/api/user/login', {
//这里面有常见的参数,包括timeout等,仅用于本次请求设置,对全局没有影响
method: 'POST',
data: params,
requestType: 'form', //post request data type
...(options || {}),
});
}
在呈上简化后的类型结构,实际可以根据类型自己更新,声明命名空间,可以保证里面类型即使与其他文件一直,只要命名空间变量不重复就没事任何事情
//声明类型,我们使用命名空间,避免类型冲突
declare namespace API {
type BaseResponse<T> = {
code: number
data: T | null
message: string
}
type LoginParams = {
account: string;
password: string;
};
type DeviceListParams = {
device_name?: string //设备名字搜索
page_num: number //1~more
page_size: number //1~more
}
}
全局请求设置
平时我们使用的时候,如果是 post 一般使用的 content-type 为 application/x-www-form-urlencoded,其以 key-value 的形式传递,非常万能,深受大家喜爱,这里只需要将全局的 requestType设置成 form即可,我们 redentials: 'include'表示携带 cookie,一般用的比较多的就这些了,还有需要的可以点进去看看其他属性
import {extend} from "umi-request";
export const request = extend({
timeout: 10000,
requestType: 'form',
credentials: 'include' //携带cookie
})
如果想在局部中改变 requestType 或者 timeout,那么直接直接写到request第二个参数里面即可
request('url', {
//这里面有常见的参数,包括timeout等,仅用于本次请求设置,对全局没有影响
method: 'POST',
data: params,
requestType: 'form', //post request data type
...(options || {}),
});
全局请求设置 + 请求拦截器
全局请求设置不多说,如果写过其他编程语言可能会对请求拦截器有所体会,这里的请求拦截器支持虽然不像其他语言一样优秀,但是也能帮助大家不少
import {extend} from "umi-request";
//全局请求参数设置
export const request = extend({
timeout: 10000,
requestType: 'form',
//注意是抛出错误后的回调方法,后面告诉你为何不用他了,当然也可以根据需要加入
// errorHandler,
credentials: 'include'
})
//假设我们有一个token,登陆才能获取,要配合加密放到header中
let token = ''
//请求request请求数据拦截器,其发生在我们写的请求之后,实际发出请求之前
request.interceptors.request.use((url, options) => {
//假设请求钱我们需要将一些令牌统一放到header中(根据实际需要处理)
//将token和加密后的sign放到一起
let headers: any = options.headers
headers['token'] = token
let sign = token + new Date().getTime()
headers['sign'] = sign
//设置完成后,要返回我们的的参数
return {
url,
options: {
...options,
headers
}
}
})
//返回数据 response 响应数据拦截器,可以拦截一些常见的状态码错误
//其发生在实际请求之后,到给我们返回的Promise之前
//根据案例演示,再加上实际使用,这个框架应用上并不是那么便利,一般仅仅用来提示打印弹窗
//我们可以稍微改进,对我们成功的进行处理,失败的给出promise
//这样状态码不对的会走到请求的.catch当中和我们的基础结构很像
request.interceptors.response.use(async (response, options) => {
console.log('response', response)
const {url, status} = response
//保证请求成功,可以再 401 登录过期时,清理用户缓存以及token等信息,并弹窗提示重新登录
if (status === 401) {
//我们可以通过 url 检查 token,赋值刷新token重新请求 token 问题,例如双token刷新
//可以给我们的请求设置 getResponse: true 就可以同时返回data和response了,可以用与更新我们的请求结果
...
}else if (status === 200) {
//我们可以直接检查返回数据内容,根据需要检查即可,一般用来检查是否成功
let data = await response.clone().json()
}
return response;
})
也简单上一下 errorHandler 的吧,这里面可以根据状态码来提示错误信息,但不建议过多使用,当服务器出现错误时,这个 error 会返回一个结构异常的 error 信息,直接以其原来结构会出错,问题挺多的
function errorHandler(error: ResponseError) {
//可以在这里处理状态码的问题,一般打印或者弹窗(弹窗有时候也很烦,如果多个不同请求,出现不同错误,就弹会同时弹出多个,自己可以看情况处理)
if (error.response.status === 401) {
console.log(error)
message.showError(error.message)
throw error
}
}
上面也介绍了,request 的拦截器还是比较好用的,response 的拦截器比较鸡肋,如果是正常的状态码没问题,如果是错误的,会自动走到errorhandle中,并且只能系统默认错误和我们reject的会进入errorhandle,这样导致 errorhandle 中的结构很是不稳定,且我们无法修改,并且一旦出现 404 或者报错之类的,会直接 errorhandle中参数都是异常的(且跟三方声明的结构不一样,挺鸡肋的),因此很不推荐
可以向我们上面一样,默认直接返回 response,请求成功,但是数据不对我们直接 reject,这样会走到外面的 .catch 中,我们可以统一处理,包括特殊的状态码等信息
使用一下看看,这样就可以了
import { request } from "./index"
//设置我们的请求吧,来个 post的
//此时拦截后,除了系统的默认错误,我们也自己 reject 返回了一个错误信息,可以查看一下看
export function loginByInfos(
params: API.LoginParams,
options?: { [key: string]: any },
) {
return request<API.BaseResponse<any>>('/url', {
method: 'POST',
data: params,
requestType: 'json', //全局设置了form,如果想传递 json 就单独传递就行了
...(options || {}),
});
}
//来个 get的
export function getDeviceList(
params?: API.DeviceListParams, //声明好自己的类型
options?: { [key: string]: any }
) {
//response根据自己的类型写上,以在编辑期间合理使用
return request<API.BaseResponse<any>>('/url', {
method: 'GET',
params,
...(options || {})
})
}