@wecity/mp-fe-gateway

1.0.4 • Public • Published

前端网关

提供给微信小程序的前端缓存/限流 SDK,通过重写 wx.request/wx.cloud.callContainer ,对请求进行前置和后置处理,从而对后端网关进行特殊时期的保护。

  1. 名词解释
缓存:对接口返回的内容(data、header、statusCode)进行缓存。

常用场景:在一定时间内不会变化的数据即可缓存,降低接口压力

主动限流:有多大比例用户可以访问到接口。

常用场景:非关键接口在流量高峰时直接不请求后端接口、抢购场景

被动限流:根据接口返回的http状态码或者业务错误码,冻结用户一段时间不能访问接口(发出请求的接口会被丢弃)。

常用场景:提前根据后端状态配置好熔断策略,不需要临时配置

快速上手

1、npm 下载

npm install @wecity/mp-fe-gateway --save-dev

2、初始化

在 app.js 里初始化

// 引入rum
// 备注:sdk要在aegis之后miniprogram-api-promise(如果有使用该库包装wx)之前
import Aegis from 'aegis-mp-sdk'
const aegis = new Aegis({
  id: 'xxxx',
  // 上报 id
  reportApiSpeed: false,
  // 接口测速
  spa: false, // spa 应用页面跳转的时候开启 pv 计算
});
const mpRateLimit = require('@wecity/mp-fe-gateway/rateLimit.min');
// 如需使用定时清理缓存需单独引入`cronCachePlugin`
const cronCachePlugin = require('@wecity/mp-fe-gateway/cronCachePlugin.min');
// 初始化sdk
mpRateLimit.init({
  url: '<%= YOUR CONFIG URL %>', // get请求策略配置信息的地址
  enable: true, // 是否关闭sdk,关闭后不会拉取配置信息,即缓存/限流等功能都不会生效,默认开启(true),开启:true,关闭:false
  debugger: true, //  是否开启控制台日志,默认关闭(false),这样在console控制台可以看到打印的信息,开启:true,关闭:false
  plugins: [cronCachePlugin], // 选择希望支持的插件
  // 全局处理函数, 写入缓存/命中缓存/被动限流/主动限流,这里可以用来做上报逻辑
  globalHandler: function (type, params) {
    switch (type) {
      // 写入缓存
      case mpRateLimit.enum.writeCache:
      // 命中缓存
      case mpRateLimit.enum.hitCache:
        // request 请求配置
        // response 返回的内容
        // cacheStorageKey 缓存Key
        // cacheTime 缓存有效时间
        const { request, cacheStorageKey = '', cacheTime } = params;
        const tempArr = cacheStorageKey.split('|');
        aegis.reportEvent({
          name: type,
          ext1: tempArr[0],
          ext2: tempArr[1],
        });
        break;
      // 被动限流
      case mpRateLimit.enum.passiveLimit:
        /*
          apiUrl:接口地址
          limitData:限流信息
              hitTime: 命中限流时间戳
              coolingTime: 冷却时间(秒)
              limitConfig: 限流配置
                 statusCode/errCode: 状态码/错误码
                 effect: 影响范围1:访问当前接口被限流,2:访问上次限流的同域名接口会被限流,不填或者填写不符合规范,默认1
        */
        const { apiUrl, limitData } = params;
        aegis.reportEvent({
          name: type,
          ext1: apiUrl,
          ext2: limitData.coolingTime,
          ext3: limitData.limitConfig.statusCode || limitData.limitConfig.errCode,
        });
        break;
      // 主动限流
      case mpRateLimit.enum.activeLimit:
        /*
         apiUrl:接口地址
         access:是否限流,false:命中限流 true:正常通行
       */
        aegis.reportEvent({
          name: type,
          ext1: params.apiUrl,
          ext2: params.access ? 'success' : 'fail',
        });
        break;
    }
  },
})
App({
  onLaunch() {
    // 包装一个自定义的全局request
    // 后续的接口请求都通过这个自定义的request
    wx.myRequest = function(options) {
      return wx.request({
        ...options,
        success: (res) => {
          // 返回了limitData({"hitTime":1651134682386,"coolingTime":10,"statusCode":503,limitType:1}),说明触发了被动限流
          // hitTime:触发时的时间戳,coolingTime:总的冷却时间(秒),被动限流才有该字段
          // remainTime:剩余多久解封(毫秒) statusCode:触发时的状态码,被动限流才有该字段
          // limitType: 1,主动限流 2、被动限流
          if (res.limitData) {
            // 被动限流处理
            if (res.limitData.limitType === 2) {
              wx.showModal({
                title: '提示',
                content: `当前访问人数太多,还需要冷却${(res.limitData.remainTime/1000).toFixed(1)}秒,请稍候再试`,
                showCancel: false,
                confirmText: '关闭',
              });
            }
          }
          options.success(res);
        },
        fail: (res) => {
          if (res.limitData) {
            // 主动限流处理
            wx.showModal({
              title: '提示',
              content: `主动限流`,
              showCancel: false,
              confirmText: '关闭',
            });
          }
          options.fail(res);
        },
      });
    }
  }
})

// 页面中使用
Page({
  fetchUserList() {
    wx.myRequest({ url: '/api/fetchUserList' })
  }
})

API

mpRateLimit.init({url,enable,debugger,globalHandler})

限流 SDK 的初始化

入参说明

参数 简介 类型 备注
url get请求策略配置信息的地址 string 地址返回的配置信息请看下面的策略配置
urlNeedTimestamp get请求策略配置信息的地址是否需要加上时间戳(url?t=Date.now()),默认false,是:true,否:false bolean
enable 是否关闭sdk,关闭后不会拉取配置信息,即缓存/限流等功能都不会生效,默认开启(true),开启:true,关闭:false bolean
debugger 是否开启限流日志,默认关闭(false),这样在console控制台可以看到打印的信息,开启:true,关闭:false bolean 验证后建议关闭
globalHandler 全局自定义处理函数,可以做上报等功能 function (type, params)

策略配置:

{
  // 是否开启主动限流, 是:1 否:0
  "openActiveLimit": 1,
  // 是否开启被动限流(当接口返回某些状态码/错误码时,自动触发被动限流), 是:1 否:0
  "openPassiveLimit": 1,

  // 插件配置
  "plugins": {
    // 实时与本地日志插件配置
    "ReportErrorLog": {
      // 是否开启小程序实时与本地日志上报,是:1 否:0
      // 关闭后实时和本地日志均不会写入上报
      "open": 1,

      // 当业务状态码不符合条件时上报
      // 影响范围:仅符合 bisDomains(业务域名白名单) 的请求才上报
      // 示例解释:!(response.data.errocde == 0 || response.data.code == '200') 时上报
      "errCodes": [
        {
          "codeKey": "errcode",
          "errCode": 0
        },
        {
          "codeKey": "code",
          "errCode": "200"
        }
      ],
      // 业务域名白名单
      "bisDomains": ["xxx.yy.com"],

      // 当存在 HTTP 状态码不符合条件时上报
      // 影响范围:所有域名的请求
      // 示例解释:[200].indexOf(response.statusCode) === -1 时上报
      "httpCodes": [
        {
          "statusCode": 200
        }
      ]
    }
  }

  // 多久后重新获取这个限流文件,单位秒
  "refreshConfigTime": 60, // 60秒后
  // 接口列表
  "apiList": [
    {
      // 路径,可以带域名
      // 同时支持 /path/** 方式,
      // 可匹配到/path/isLoginV1 或者/path/isLoginV2, 
      // ** 只能匹配到非/内的路径字符,无法匹配到/
      "path": "/path/isLoginV2",
      // 主动限流配置
      "activeLimit": {
        // 初始百分比
        "percent": 50,
        // 请求接口失败后,下次提升10%的成功率(接口请求成功后,成功率重置回原来初始百分比),默认是0
        "increaseNum": 10,
      },
      // 被动限流配置
      "passiveLimit": {
        // 根据接口返回的状态码进行被动限流
        "httpCodes": [
          // 下面配置解释(配置了当前接口限流后,后续请求的所有接口都会限流):
          // wx.request访问isLoginV2接口,回调函数(success)因为503状态码返回了限流信息limitData:{"statusCode":503,"limitData":{"hitTime":1651134682386,"remainTime":3000,"hitTime":1651134682386,"coolingTime":10,"statusCode":503}},
          // 那么10秒内,通过wx.request访问A/B/C接口,回调函数(fail)会直接返回限流信息limitData(刚刚isLoginV2接口返回的内容):{"statusCode":503,"limitData":{"hitTime":1651134682386,"remainTime":3000,"coolingTime":10,"statusCode":503}}
          // 业务方根据limitData去做定制处理
          {
            "statusCode": 503, // 必填:状态码
            "effect": 2, // 影响范围1:访问当前接口被限流,2:访问上次限流的同域名接口会被限流,不填或者填写不符合规范,默认1
            "coolingTime": 10, // 必填:秒,限流冷却时间,在这段时间发起的请求不会到达后端,不填或者填写不符合规范,默认6秒
          }
        ],
        // 根据接口body返回的errcode进行被动限流
        "errCodes": [
          {
            "codeKey": "errcode", // 必填:错误码的键 errcode code?
            "errCode": 10002, // 必填:body返回的错误码
            "effect": 2, // 必填:影响范围1:访问当前接口被限流,2:访问上次限流的同域名接口会被限流
            "coolingTime": 10, // 必填:秒,限流冷却时间,在这段时间发起的请求不会到达后端
          }
        ],
      },
      // 缓存配置   resp.statusCode / get(resp.data, codeKey)
      "cache": {
        // 必填:该请求缓存时间,单位为秒, 大于0的数字
        "cacheTime": 60,
        "cronCacheTime": '* 0 * * *', // 每日0点失效
        // 缓存参数值,会根据该值确定缓存是否生效
        // 必填:提供的参数为 query/data/header,可以通过模版进行组合
        "cacheKey": "${header.sid}-${data['x-table']}-${data.params[0]['x-table']}-${query.id}",

        // 必填:状态码
        "statusCode": 200, // 必填:http response 状态码
        "codeKey": "errcode", // 必填:http response data 业务状态码字段
        "errCode": 0 // // 必填:http response data 业务状态码
      }
    }
  ]
}

mpRateLimit.safeFetchCfg(apiUrl)

获取限流配置,返回promise对象

使用场景:利用sdk的配置下发能力,把业务配置放到限流配置里,实现业务逻辑

apiUrl传入则获取对应api的配置规则,不传则返回整个json配置文件
// 读取配置文件
rateLimit.safeFetchCfg("/path/isLoginV2").then(res=> {
  //会返回配置文件apiList中/path/isLoginV2的配置
console.log(res)
}).catch(()=> {})

mpRateLimit.clearCache()

清除所有rateLimit设置的缓存数据, 可以使用在不同用户登陆时 又没有不同用户唯一标识情况下数据错乱时,做清除用户处理。

mpRateLimit.checkCacheByDate("2022-05-05 12:30:45")

根据服务器时间更正 cache是否依然在缓存有效期,如果不在则清理

mpRateLimit.clearCacheByUrlPath(urlPath)

清理urlPath 匹配成功的所有缓存内容,使用正则表达式匹配 例如

// 如果json里 apiList 里 path 配置为 /api/fetchUserList/get /api/fetchUserList/put  
mpRateLimit.clearCacheByUrlPath('/api/fetchUserList/get') // 清理路径/api/fetchUserList/get的缓存
mpRateLimit.clearCacheByUrlPath('/api/fetchUserList/([a-z]+)') // 清理/api/fetchUserList/get, /api/fetchUserList/put的缓存 

mpRateLimit.clearCacheByUrlPath('/api/fetchUserList/get', {
  cacheKeyData: {
    header: {
      sid: '1212',
    },
    query: {
      qid: '222',
    },
    data: {
      did: '333'
    }
  }
}) // 精准清理 具体某一条的 缓存

内置插件

点击查看插件详细介绍

1. 实时与本地日志上报插件

2. Cron 格式缓存时间插件

其他说明

  1. 因限流配置为异步拉取,首次生效期可能会有一定的延迟,取决于限流配置拉取回来的时间。
  2. 用户登录/退出建议清理下缓存。另外根据具体业务情况清理缓存。
  3. 当cdn挂了,使用上次请求回来的配置规则。
  4. 改小cacheTime会重新加载数据,不会走缓存;如果不想走缓存,把cacheTime设置为0。

Readme

Keywords

Package Sidebar

Install

npm i @wecity/mp-fe-gateway

Weekly Downloads

0

Version

1.0.4

License

ISC

Unpacked Size

64.1 kB

Total Files

21

Last publish

Collaborators

  • loopzhou
  • zystylish
  • brian_zhang
  • legendlu
  • fenfeizeng
  • colinczhu
  • easonruan
  • yikazhu
  • daniel-dx
  • domy
  • delenzhang
  • vickiliang
  • derrickliu
  • xiaoyaojones
  • smileswlin
  • jillysong
  • allennzhang
  • sharryliao
  • pechelhuang
  • phspan