Tutorial: [基础能力] 灵活易扩展的请求管理

[基础能力] 灵活易扩展的请求管理

功能

  • 发起网络请求
    • 基础功能、参数、用法同小程序原生网络api
  • Promise化
    • 调用结果改以Promise形式返回,便于时序管理
    • 兼容success、fail、complete回调
  • 灵活组装
    • 可以方便地在请求前后添加/移除各种扩展逻辑
    • 设置默认表单类型
    • 植入登录态相关逻辑
    • 植入cookie相关逻辑
    • 网络异常监听&自动恢复
    • 云函数http化
    • ……

使用

  1. fancy-mini setup
  2. 引入&配置
  //项目入口文件(app.js/app.wpy/app.vue/main.js/……,因框架而异)
  import './lib/appPlugin';  //负责各种小程序级公共模块的引入和配置
  //appPlugin.js, 负责各种小程序级公共模块的引入和配置
  import Requester from "fancy-mini/lib/request/Requester";
  import {registerToThis} from 'fancy-mini/lib/wepyKit';

  //实例创建
  const requester = new Requester(); //请求管理器

  //请求管理器配置
  requester.config({
    //使用的底层网络api
    underlayRequest: wx.request,
    
    //以插件的形式添加/移除各种扩展逻辑
    plugins: [
      //各种插件,详见下文
    ]
  });
  
  //将请求模块相关功能注册到this上,方便页面/组件直接使用
  const propMapThis2Requester = { //命名映射,key为this属性名,value为requester属性名, '*this'表示requester自身
    '$requester': '*this', // this.$requester 对应 requester
    '$http': 'request', // this.$http() 对应 requester.request()
    //...
  };

  for (let [thisProp, requesterProp] of Object.entries(propMapThis2Requester)) {
    let requesterTarget = requesterProp === '*this' ? requester : requester.makeAssignableMethod(requesterProp);
    registerToThis(thisProp, requesterTarget);
  }
  
  //导出部分模块,便于独立js文件使用
  export {
    requester,
  }

  1. 小程序各处使用
  //独立js文件,手动引入appPlugin模块并使用相关功能
  import {requester} from '../../lib/appPlugin';

  async test(){
    let dataRes = await requester.request({
      url: 'https://xxx',
      data: {
      }
    });
    
    console.log('dataRes:', dataRes); //请求结果,即为后端接口返回内容 e.g.后端返回"{respCode:0}",则dataRes={respCode: 0}
  }
  //页面/组件,可以直接通过this使用相关功能
  async test(){
    let dataRes = await this.$http({
      url: 'https://xxx',
      data: {
        
      }
    });
    
    console.log('dataRes:', dataRes); //请求结果,即为后端接口返回内容 e.g.后端返回"{respCode:0}",则dataRes={respCode: 0}
  }

扩展逻辑-概述

  • 说明
    • 各种扩展逻辑以插件的形式在requester上配置,可以根据需要添加/移除
    • 插件对象应为BasePlugin子类实例
    • 注意插件顺序,配置顺序即为执行顺序
  • 配置示例
  import FormPlugin from 'fancy-mini/lib/request/plugin/FormPlugin';
  import LoginPlugin from 'fancy-mini/lib/request/plugin/LoginPlugin';
  import CookiePlugin from 'fancy-mini/lib/request/plugin/CookiePlugin';
  import FailRecoverPlugin from 'fancy-mini/lib/request/plugin/FailRecoverPlugin';
  import CloudFuncPlugin from 'fancy-mini/lib/request/plugin/CloudFuncPlugin';

  requester.config({
    //...
    
    //以插件的形式添加/移除各种扩展逻辑
    plugins: [
      //表单插件,修改表单默认处理方式
      new FormPlugin({
        defaultContentType: 'application/x-www-form-urlencoded' //指定默认表单类型
      }),
      //登录插件,自动检查、获取、更新登录态
      new LoginPlugin({
        loginCenter,
        apiAuthFailChecker
      }),
      //cookie插件,自动读取&写入cookie
      new CookiePlugin({
        cookie
      }),
      //网络异常处理插件,监听&处理网络异常
      new FailRecoverPlugin({
        requestFailRecoverer
      }),
      //云函数插件,以http接口的形式使用云函数
      new CloudFuncPlugin({
        fakeDomain: 'cloud.function'
        fakeRootPath: '/'
      }),
    ]
  })

扩展逻辑-表单插件

  • 功能
    修改表单默认处理行为

    1. 将请求头部中的content-type默认值改为构造函数中指定的defaultContentType
  • 使用

  import FormPlugin from 'fancy-mini/lib/request/plugin/FormPlugin';
  
  requester.config({
    //...
    
    //以插件的形式添加/移除各种扩展逻辑
    plugins: [
      //表单插件,修改表单默认处理方式
      new FormPlugin({
        defaultContentType: 'application/x-www-form-urlencoded' //指定默认表单类型
      })
    ]
  })

扩展逻辑-登录插件

  • 功能
    在请求前后植入登录态检查和处理逻辑
    1. 在requester上注册一个requestWithLogin方法,用于调用需要登录态的接口
    2. 请求发出前,若未登录,则先触发登录,然后再发送接口请求
    3. 请求返回后,若判断后端登录态已失效,则自动重新登录重新发送接口请求,并以重新请求的结果作为本次调用结果返回
  • 使用
    参见[基础能力] 健壮高效的登录机制

扩展逻辑-cookie插件

  • 功能
    在请求前后植入cookie相关逻辑
    1. 请求发出前,在请求头部中注入当前环境cookie信息
    2. 请求返回后,接收返回结果头部中的cookie信息,并写入当前环境cookie中
  • 使用
    参见[基础能力] cookie机制

扩展逻辑-网络异常处理插件

  • 功能
    监听网络异常情况,并进行恢复处理
  • 使用
  import FailRecoverPlugin from 'fancy-mini/lib/request/plugin/FailRecoverPlugin';
  
  requester.config({
    //...
    
    //以插件的形式添加/移除各种扩展逻辑
    plugins: [
      //网络异常处理插件,监听&处理网络异常
      new FailRecoverPlugin({
        requestFailRecoverer({res, options, resolve, reject}){
          //展示网络异常界面,提示用户“点击屏幕任意位置重试”
          //点击重试
          //重试成功,resolve(重试后的请求结果)
          //发生异常,reject(异常详情)
        }
      }),
    ]
  })

扩展逻辑-云函数插件

  • 功能
    将云函数封装成http接口形式使用,便于:
    1. 使用requester提供的各种逻辑扩展能力
    2. 后续在云函数和后端服务器之间进行各种业务的相互迁移
  • 使用
  1. 配置
  //appPlugin.js
  import CloudFuncPlugin from 'fancy-mini/lib/request/plugin/CloudFuncPlugin';
  
  requester.config({
    //...
    
    //以插件的形式添加/移除各种扩展逻辑
    plugins: [
      //云函数插件,以http接口的形式使用云函数
      new CloudFuncPlugin({
        fakeDomain: 'fancy.com', //虚拟域名
        fakeRootPath: '/demos/cloud/' //虚拟路径
      }),
    ]
  })
  1. 调用
  //则调用指定虚拟域名虚拟路径下的接口
  let res = await requester.request({
    url: 'https://fancy.com/demos/cloud/xxx?a=1&b=2'
  });
  //等价于调用对应云函数
  let res = await wx.cloud.callFunction({
    name: 'xxx',
    data: {
      a: "1",
      b: "2",
    }
  })
  1. 云函数约定
  exports.main = async (event, context) => {
    //云函数格式约定:

    let {a, b} = event; //调用方传入的参数可以通过event获取
    a = Number(a); //参数类型统一为string
    b = Number(b);

    //此外,还会额外拼入一些http相关参数
    let {reqHeader} = event; //http请求header信息
    console.log(reqHeader.cookie); //header中的cookie字段会解析成对象格式,形如:{uid: 'xxx'}

    //处理结果正常返回
    let result = { sum: a+b };

    //此外,有一些保留字段可以用于设置http相关参数
    result.resStatusCode = 200; //设置http状态码
    result.resHeader = {}; //设置http返回结果中的header信息
    result.resHeader['Set-Cookie'] = [ //同一header有多条记录时,以数组形式设置
      'uid=xxx;expires=111',
      'sessionKey=yyy;expires=222'
    ]

    return result;
  }

自定义扩展逻辑

  • 功能
    在请求前后添加各种自定义逻辑。

  • 使用

  1. 编写插件
  import BasePlugin from 'fancy-mini/lib/request/plugin/BasePlugin';
  
  //插件需继承插件基类BasePlugin
  class DIYPlugin extends BasePlugin {
    //各种自定义逻辑实现
    //可重写节点参见BasePlugin文档,实现示例可参考 api查询 小节中各插件源码
  }
  
  export default DIYPlugin;
  1. 使用插件
  //appPlugin.js
  import DIYPlugin from './request/plugin/DIYPlugin';
  
  requester.config({
    //...
    
    //以插件的形式添加/移除各种扩展逻辑
    plugins: [
      //自定义插件
      new DIYPlugin({
        //自定义配置...
      }),
    ]
  })

api查询