@wecity/mp-fe-gateway
v1.0.4
Published
小程序前端网关,提供给微信小程序的前端限流 SDK,通过限流配置对 wx.request/wx.cloud.callContainer 进行前置拦截,从而对后端网关进行特殊时期的保护。
Downloads
6
Maintainers
Keywords
Readme
前端网关
提供给微信小程序的前端缓存/限流 SDK,通过重写 wx.request/wx.cloud.callContainer ,对请求进行前置和后置处理,从而对后端网关进行特殊时期的保护。
- 名词解释
缓存:对接口返回的内容(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 格式缓存时间插件
其他说明
- 因限流配置为异步拉取,首次生效期可能会有一定的延迟,取决于限流配置拉取回来的时间。
- 用户登录/退出建议清理下缓存。另外根据具体业务情况清理缓存。
- 当cdn挂了,使用上次请求回来的配置规则。
- 改小cacheTime会重新加载数据,不会走缓存;如果不想走缓存,把cacheTime设置为0。