react中axios封装ajax,从零搭建React项目脚手架(系列一:基于Axios封装一个带缓存功能的请求方法)...

前言

自入职以来,感觉生活着实是变得很忙碌,虽然是实习生,但工作依然是被安排的很充足。每天等着9点领完夜宵再下班已经是常态了,回到出租屋洗完澡已是10点,此后虽然还想着再学些什么却又更想还是看一会儿视频就睡觉好了。五一假期亦没有出行,一是没有想一起出游的伙伴,二是确实想好好休息下,与其出去受罪我还是想在学校歇着,玩一玩好久没动的游戏,看看书什么的。

说回此篇文章,在我实习经历中,我自己一直都在做的是类似于打杂的工作,主要时间都是在基于师兄建好的框架上进行页面的开发,虽然说在项目中这样的工作是占了绝大部分,但毫无疑问,那些前期基础的工作对于项目来说才是举足轻重的,是否掌握这些工程化的知识,也是区分前端工程师和前端切图仔的重要标准。出于掌握并分享知识的目的,我决定分为几个系列步骤,逐步搭建一个自己的React项目脚手架。

封装axios

将axios根据业务的需求封装为对外暴露的request方法,整体代码还是比较简单明了的,这里就不再过多解释,代码中也有注释,其中还用到了一个decodehtml方法,是用来将后端返回的富文本错误信息进行展示。

/** decodeHtml */

export const decodeHtml = (html: string): string => {

let oDiv = document.createElement('div');

oDiv.innerHTML = html;

const textContent = oDiv.textContent;

oDiv = null;

return textContent;

};

以下为request方法的代码(src/utils/request.ts)

import { Message, Dialog } from '@alifd/next';

import axios, { AxiosRequestConfig } from 'axios';

import { decodeHtml } from '@/utils';

export interface IRequest extends AxiosRequestConfig {

url: string;

/** 请求参数,当method为post的时候请使用data属性 */

params?: any;

/** 当method为post的时候使用data属性 */

data?: any;

/**

* 是否缓存数据,相同url数据只请求一次,后面的请求都使用第一次请求的数据

*/

cache?: boolean;

/** 更据 cacheKey 进行缓存, 当cache 为true时生效 */

cacheKey?: string;

/**

* 错误时是否Message提示错误信息, 默认开启

*/

enableErrorMsg?: boolean;

// 缓存有效期

maxAge?: number;

[key: string]: any;

}

// 缓存存储对象,当项目大了的时候考虑释放内存,目前不需要

const request_cache = {};

export interface IResult {

success?: boolean;

code?: string;

message?: string;

data?: any;

[key: string]: any;

}

// 设置为ajax请求

axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

/**

* 数据请求

* @example

* request({

* url: '/a/b/c',

* params: {}

* })

* // res.success === true的时候执行 then

* .then(res => {...})

* // res.success === false 的时候执行 catch

* .catch(res => {...})

*

* 请配合 `ahooks` 的 `useRequest` 使用 https://ahooks.js.org/hooks/async#dependent-request

*/

export default ({

cache = false,

enableErrorMsg = true,

cacheKey = '',

maxAge = Infinity, //过期时间

...params

}: IRequest) => {

// 本地缓存,只请求一次

if (cache && request_cache[`${params.url}-${cacheKey}`]) {

if (request_cache[`${params.url}-${cacheKey}`].then) {

return request_cache[`${params.url}-${cacheKey}`];

} else if (

new Date().getTime() -

request_cache[`${params.url}-${cacheKey}`].cacheTime <

maxAge

) {

return new Promise(resolve => {

resolve(request_cache[`${params.url}-${cacheKey}`].res);

});

}

} else if (request_cache[`${params.url}-${cacheKey}`]) {

delete request_cache[`${params.url}-${cacheKey}`];

}

if (params.method && params.method.toLowerCase() === 'post') {

// post时传入参数是data字段

params.data = params.data || params.params || undefined;

// params.data = qs.stringify(params.data); // 和后端约定 post请求用json的方式传递数据,所以关掉

params.params = undefined;

params.headers = params.headers || {

'Content-Type': 'application/json;charset=UTF-8', // 和后端约定 post请求用json的方式传递数据

};

// 如果需要做csrf可以采用以下方案,需要后端先在接口返回信息中设置cookie

// if (!isLocal()) {

// const csrfToken = getCookie('XSRF-TOKEN');

// if (csrfToken) {

// params.headers['X-XSRF-TOKEN'] = csrfToken;

// } else {

// Message.error('cookie获取失败'); // XSRF-TOKEN cookie 缺失

// throw new Error('cookie获取失败');

// }

// }

} else if (

!params.method ||

(params.method && params.method.toLowerCase() === 'get')

) {

// get时传入的参数是params字段

params.params = params.params || params.data || undefined;

}

const servicePromise = new Promise((resolve, reject) => {

axios(params)

.then(({ data: res, status }: IResult) => {

const { message, success, data, code } = res;

if (success && status === 200) {

// 成功

// 需要缓存的数据缓存下来

cache &&

(request_cache[`${params.url}-${cacheKey}`] = {

res,

cacheTime: new Date().getTime(),

});

resolve(res);

} else if (code === '9003') {

// 状态过期重定向,后端code为9003,这里的code每个团队有自己的规范

Dialog.confirm({

content: `状态已过期,是否重新刷新页面? `,

onOk: () => {

window.location.reload();

},

});

} else if (data?.applyUrl) {

// 临时处理无权限跳转

window.location.href = data.applyUrl;

reject(res);

} else {

// 失败

// 失败时是否展示错误信息

enableErrorMsg &&

Message.error(

`[${params.apiName || params.url}]: ${decodeHtml(message)}`

);

reject(res);

}

})

.catch(e => {

// 接口非200 || 接口非304

enableErrorMsg && Message.error(`[http]: ${e}`);

reject(e);

});

});

//缓存这里需要考虑一种情况是,在第二次请求发出时,第一次请求还未完成

//那么可以先把第一次请求操作缓存,第二次请求时判断若还在pending中,则返回promise对象,否则返回结果

if (cache) {

request_cache[`${params.url}-${cacheKey}`] = servicePromise;

}

return servicePromise;

};

使用方式

应用中所有的请求方法都放在 src/services/ 目录下,每个模块/页面使用的请求方法放在一个对应的js/ts文件中。

//src/services/examplePage.ts

import request from '@/utils/request';

export const exampleApi = ({ data, ...elseConfig }) => {

return request({

url: `/api/reputation/evaluation/deepInsight/emotion`,

method: 'post',

data,

...elseConfig,

});

};

在页面中使用,推荐搭配ahooks 的 useRequest使用

import {exampleApi} from '@/services/examplePage.ts';

import { useRequest } from 'ahooks';

const { data, error, loading } = useRequest(()=>exampleApi({

data:{

yourInfo:''

},

cache:true,

maxAge:360000

});

作者:羽晋

链接:https://juejin.cn/post/6957945548607324191

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值