最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 从零搭建React项目脚手架(系列一:基于Axios封装一个带缓存功能的请求方法)

    正文概述 掘金(羽晋)   2021-05-03   447

    前言

    自入职以来,感觉生活着实是变得很忙碌,虽然是实习生,但工作依然是被安排的很充足。每天等着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  
      });
    
    

    起源地下载网 » 从零搭建React项目脚手架(系列一:基于Axios封装一个带缓存功能的请求方法)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元