Koa学习之路——实现节流中间件

707 阅读2分钟

今天简单解释下令牌桶法,系统会以一定的速率往桶里添加令牌,处理请求前,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则返回失败。

大概描述如下:

所有的请求在处理之前都需要拿到一个可用的令牌才会被处理; 获取不到令牌,则请求返回失败 根据限流大小,设置按照一定的速率往桶里添加令牌; 桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;

实现关键点:

  1. 初始化固定数量的令牌放入令牌桶中
  2. 初始化和开启一个定时的任务,定时往令牌桶添加令牌
  3. 提供一个获取令牌的方法,获取一个令牌,令牌桶中减一,如果令牌桶中为空,返回失败
class TokenLimiter {
  constructor(limit) {
    this.limit = limit
    this.arrayQueue = []
    this.init()
    this.start()
  }
  //初始化令牌数量
  init() {
    console.log(1)
    for (let i = 0; i < this.limit; i++) {
      this.arrayQueue.push('1')
    }
  }
  //获取令牌
  getToken() {
    return !!this.arrayQueue.shift()
  }
  //开启一个定时器在特定的时间初始化令牌
  start() {
    setInterval(() => {
      if (this.arrayQueue.length === 0) {
        console.log(`令牌没有了,正在补充。。。。。`)
        this.init()
      }
    },1000)
  }
}

module.exports = TokenLimiter

那么我们如何在Koa中使用它呢!如下:

const Koa = require('koa')
const Router = require('koa-router')
const moment = require('moment')

const TokenLimiter = require('./tokenLimiter')

const router = new Router()
const app = new Koa()
//实例化TokenLimiter类,传入你初始化的令牌数
const tokenLimiter = new TokenLimiter(10)

const data = require('./data.json')

const limitWrapper = async (ctx, next) => {
  const flag = tokenLimiter.getToken()
  if (!flag) {
    ctx.response.body = '网络错误'
    ctx.response.status = 500
  }
  await next()
}

app.use(limitWrapper)

const leaderboard = async (ctx) => {
  const { type, dateType } = ctx.query
  const filterDate = (date) => moment(moment().subtract(dateType === 'd' ? 0 : 1, dateType).format('YYYY-MM-DD')).isSameOrBefore(date)
  ctx.response.body = data.filter(x => x.type === type && filterDate(x.date))
}

router.get('/leaderboard', leaderboard)

app.use(router.routes())

app.listen(3009)

以上就是如何在Koa实现节流思路,看完后觉得还行,给个赞哦。
还有本人有丰富的AWS Lambda使用经验,有对这方面感兴趣的小伙伴们可以探讨下