最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 前端API模块方案

    正文概述 掘金(云嘤)   2021-05-10   528

    什么是前端API模块?

    首先明确一个概念,本文说的前端API模块指的是什么?

    在前端代码中(本文不包括BFF,BFF也划分到“后端”)存在请求后端服务接口代码,通常情况下,一个后端接口可能被多个页面使用,所以我们通常会把后端接口API相关的前端代码放在一个模块中统一管理,在需要发起请求的代码中,引用该模块,然后使用指定API的方法发起请求,从而达到复用代码、统一管理的目的,而这个管理API的模块,我将它命名为“前端API模块”。

    因为我也不太清楚我们前端圈里怎么命名这东西,所以我姑且先这么称呼它吧。如果可以的话,在评论区告诉我这个应该怎么称呼更好?!

    历史方案

    首先说一下目前项目的方案,以及存在的问题。

    方案:每个服务管理独立的API模块

    我们将一个大分类的功能模块称之为服务,比如产品服务、用户服务等,然后前后端都使用服务分类将代码划分为不同的目录或者微服务。

    后端的接口通过微服务提供,比如产品服务的API地址为 /api/products/v1/xxx,用户服务的API地址为 /api/users/v1/yyy 等。

    前端类似地在每个服务目录下,提供单独的apis模块,比如在products目录下,有一个 apis.js 文件导出apis模块,该模块定义所有后端products服务的API地址常量。在页面代码中发起请求时,通过引入该模块,然后使用该模块导出的常量名称,然后使用请求方法发起请求。

    // ./products/apis.js
    
    const VERSION = 'v1';
    const SERVICE = 'products';
    
    const PRODUCT_LIST = `/api/${SERVICE}/${VERSION}/list`;
    
    export default {
      PRODUCT_LIST,
    };
    
    // ./products/pages/list.js
    
    import APIS from '../apis';
    import axios from 'axios';
    
    const { PRODUCT_LIST } = APIS;
    
    axios.get(PRODUCT_LIST, {
      params: {
        pageIndex: 1,
        pageSize: 10,
      }
    }).then(() => {
      // ...
    }).catch(() => {
      // ...
    });
    
    

    使用这种方案,当API接口地址发生变化时,只需要修改apis.js中的常量值即可。

    问题

    1、当多个服务使用相同的API时,需要修改多个服务的API,容易出现漏改情况;

    2、当业务代码使用不规范时,没有按照规范引入API模块,修改API地址时,出现漏改情况;

    3、业务代码还需要自行引入请求库,这些原本也可以内聚到API模块中实现;

    改良方案

    所以需要改良方案,解决历史方案存在的问题。

    1、抽取到公共服务API模块或者独立的API服务

    将所有的API都收起来,放在公共服务或者单独一个服务中进行管理,不再分散到每个服务中去。这样做的好处是,没有产品服务都使用同一个API服务,方便进行统一规范的管理,不管是API的调整,还是请求拦截,又或者是其他需要增强的功能,都只需要在一个API服务中进行变更,而不需要在每个产品服务中修改。这样,也就不会出现由于需要改动多处导致修改错误、漏改的问题。

    当然,任何方案都不是完美的,方案的选择永远都是权衡的艺术。

    这种方案的问题也会存在一些不尽人意的问题。

    首先,它会导致公共资源加载成本和内存成本,会存在一定的冗余。公共资源加载时需要首先加载API模块代码,API模块导出的对象,需要长期占用内存空间。针对问题,我们可以通过按需加载的方式减少资源加载成本,以及利用缓存(sessionStorage等)将数据缓存下来,需要时再读取的方式减少内存成本。

    其次,开发过程中增加了代码管理成本。当公共服务代码和产品服务代码分开代码库时,需要注意不同代码库的代码版本(通常指的是代码分支),否则可能会出现产品服务引用了历史版本的公共模块,而导致缺少相应API、或者API不争气的问题。

    总的来说,新的方案是利大于弊的。

    2、API模块提供更加完善的功能

    之前的方案中,只是提供了API地址,功能很受限,所以新的方案中,我们不仅提供API地址,还需要把每个API作为一个完整的请求函数,提供默认的请求参数值,增强请求的容错性。

    // ./apis/products.js
    
    import axios from 'axios'; 
    
    const VERSION = 'v1';
    const SERVICE = 'products';
    
    const PRODUCT_V1 = `/api/${SERVICE}/${VERSION}`;
    
    // 获取产品列表接口
    export function getProductList(params = {}) {
      return axios.get(`${PRODUCT_V1}/list`, {
        params: {
          // 默认参数
          pageIndex: 1,
          pageSize: 10,
          
          // 传入的参数
          ...params,
        }
      });
    }
    
    // 新增产品接口
    export function addProduct(data) {
      if(!data || !data.name) {
        return Promise.reject('The [name] is required!');
      }
      return axios.post(`${PRODUCT_V1}`, {
          data: {
              ...data,
              name: data.name.trim(),
          }
      });
    } 
    
    // 修改产品接口
    export function addProduct(params, data) {
      if(!params || !params.id) {
           return Promise.reject('The [id] in params is required!');
      }
      if(data && data.name) {
           return Promise.reject('The data.name is not allowed to be modified!');
      }
      return axios.put(`${PRODUCT_V1}/${params.id}`, {
          data,
      });
    }  
    
    
    // ./apis/index.js
    import axios from 'axios'; 
    export * as products from './products';
    
    // 拦截请求
    axios.interceptors.request.use(function (config) {
      // Do something before request is sent
      return config;
    }, function (error) {
      // Do something with request error
      return Promise.reject(error);
    });
    
    // 拦截响应
    axios.interceptors.response.use(function (response) {
      // Any status code that lie within the range of 2xx cause this function to trigger
      // Do something with response data
      return response;
    }, function (error) {
      // Any status codes that falls outside the range of 2xx cause this function to trigger
      // Do something with response error
      return Promise.reject(error);
    });
    
    // ./products/pages/list.js
    import { products } from './apis';
    
    const { getProductList } = products;
    
    getProductList()
      .then(() => {
      	// ...
        })
        .catch(() => {
      	// ...
        })
    

    起源地下载网 » 前端API模块方案

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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