通过Node和Redis进行API速率限制

标签: node redis api | 发表时间:2020-09-15 13:53 | 作者:杭州程序员张张
出处:https://juejin.im/frontend

原文: codeburst.io
作者:Joyce Lin

速率限制可以保护和提高基于API的服务的可用性。如果你正在与一个API对话,并收到HTTP 429 Too Many Requests的响应状态码,说明你已经被速率限制了。这意味着你超出了给定时间内允许的请求数量。你需要做的就是放慢脚步,稍等片刻,然后再试一次。

为什么要速率限制?

当你考虑限制你自己的基于API的服务时,你需要在用户体验、安全性和性能之间进行权衡。

控制数据流的最常见原因是保持基于API的服务的可用性。但也有安全方面的好处,一次无意或有意的入站流量激增,就会占用宝贵的资源,影响其他用户的可用性。

通过控制传入请求的速率,你可以:

  • 保障服务和资源不被“淹没”。
  • 缓和暴力攻击
  • 防止分布式拒绝服务(DDOS)攻击

如何实施限速?

速率限制可以在客户端级别,应用程序级别,基础架构级别或介于两者之间的任何位置实现。有几种方法可以控制API服务的入站流量:

  • 按用户:跟踪用户使用API密钥、访问令牌或IP地址进行的调用
  • 按地理区域划分:例如降低每个地理区域在一天的高峰时段的速率限制
  • 按服务器:如果你有多个服务器处理对API的不同调用,你可能会对访问更昂贵的资源实施更严格的速率限制。

你可以使用这些速率限制中的任何一种(甚至组合使用)。

无论你选择如何实现,速率限制的目标都是建立一个检查点,该检查点拒绝或通过访问你的资源的请求。许多编程语言和框架都有实现这一点的内置功能或中间件,还有各种速率限制算法的选项。

这是使用Node和Redis制作自己的速率限制器的一种方法:

  1. 创建一个Node应用
  2. 使用Redis添加速率限制器
  3. 在Postman中测试

GitHub上查看代码示例。

在开始之前,请确保已在计算机上安装了Node和Redis。

步骤1:建立Node应用程序

从命令行设置一个新的Node应用。通过CLI提示,或添加 —yes 标志来接受默认选项。

   $ npm init --yes
复制代码

如果在项目设置过程中接受了默认选项,则为入口点创建一个名为 index.js 的文件。

   $ touch index.js
复制代码

安装Express Web框架,然后在 index.js 中初始化服务器。

   const express = require('express')
const app = express()
const port = process.env.PORT || 3000

app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
复制代码

从命令行启动服务器。

   $ node index.js
复制代码

回到 index.js 中,创建一个路由,先检查速率限制,如果用户没有超过限制再允许访问资源。

   app.post('/', async (req, res) => {
  async function isOverLimit(ip) {
    // to define
  }
  // 检查率限制
  let overLimit = await isOverLimit(req.ip)
  if (overLimit) {
    res.status(429).send('Too many requests - try again later')
    return
  }
  // 允许访问资源
  res.send("Accessed the precious resources!")
})
复制代码

应用级速率限制

在下一步中,我们将定义速率限制器函数 isOverLimit

步骤2:使用Redis添加速率限制器

Redis是一个内存中键值数据库,因此它可以非常快速地检索数据。使用Redis实施速率限制也非常简单。

  • 存储一个像用户IP地址一样的key。
  • 增加从该IP发出的调用数量
  • 在指定时间段后使记录过期

下图所示的限速算法是一个 滑动窗口计数器的例子。一个用户如果提交的调用数量适中,或者随着时间的推移将它们分隔开,就永远不会达到速率限制。超过10秒窗口内最大请求的用户必须等待足够的时间来恢复其请求。

限速算法:滑动窗口计数器

从命令行为Node安装一个名为ioredis的Redis客户端。

   $ npm install ioredis
复制代码

在本地启动Redis服务器。

   $ redis-server
复制代码

然后在 index.js 中要求并初始化Redis客户端。

   const redis = require('ioredis')
const client = redis.createClient({
  port: process.env.REDIS_PORT || 6379,
  host: process.env.REDIS_HOST || 'localhost',
})
client.on('connect', function () {
  console.log('connected');
});
复制代码

定义我们上一步开始写的isOverLimit函数,按照Redis的这个模式,按照IP来保存一个计数器。

   async function isOverLimit(ip) {
  let res
  try {
    res = await client.incr(ip)
  } catch (err) {
    console.error('isOverLimit: could not increment key')
    throw err
  }
  console.log(`${ip} has value: ${res}`)
  if (res > 10) {
    return true
  }
  client.expire(ip, 10)
}
复制代码

这就是速率限制器。

当用户调用API时,我们会检查Redis以查看该用户是否超出限制。如果是这样,API将立即返回HTTP 429状态代码,并显示消息 Too many requests — try again later 。如果用户在限制之内,我们将继续执行下一个代码块,在该代码块中,我们可以允许访问受保护的资源(例如数据库)。

在进行速率限制检查期间,我们在Redis中找到用户的记录,并增加其请求计数,如果Redis中没有该用户的记录,那么我们将创建一个新记录。最后,每条记录将在最近一次活动的10秒内过期。

在下一步中,请确保我们的限速器正常运行。

步骤3:在Postman中进行测试

保存更改,然后重新启动服务器。我们将使用Postman将 POST 请求发送到我们的API服务器,该服务器在本地运行,网址为 http:// localhost:3000

在速率限制内

继续快速连续发送请求以达到你的速率限制。

超过速率限制-HTTP 429请求过多

关于限速的最终想法

这是Node和Redis的速率限制器的简单示例,这只是开始。有一堆策略和工具可以用来架构和实现你的速率限制。而且还有其他的增强功能可以通过这个例子来探索,比如:

  • 在响应正文或作为 Retry-after 标头中,让用户知道在重试之前应该等待多少时间
  • 记录达到速率限制的请求,以了解用户行为并警告恶意攻击
  • 尝试使用其他速率限制算法或其他中间件

请记住,当你研究API限制时,你是在性能、安全性和用户体验之间进行权衡。你理想的速率限制解决方案将随着时间的推移而改变,同时也会考虑到这些因素。

继续阅读其他高赞文章

最近整理了一份优质视频教程资源,想要的可以关注我公众号即可免费领取哦!

相关 [node redis api] 推荐:

通过Node和Redis进行API速率限制

- - 掘金前端
速率限制可以保护和提高基于API的服务的可用性. 如果你正在与一个API对话,并收到HTTP 429 Too Many Requests的响应状态码,说明你已经被速率限制了. 这意味着你超出了给定时间内允许的请求数量. 你需要做的就是放慢脚步,稍等片刻,然后再试一次. 当你考虑限制你自己的基于API的服务时,你需要在用户体验、安全性和性能之间进行权衡.

RedBridge: Redis for HTTP API[推荐]

- yonghai - 运维进行时
       RedBridge 是一款基于redis 的 HTTP API. 使用LUA 直接跟redis 交互. (类似数据库的存储过程) 高效的实现复杂的业务逻辑. 项目网址:http://code.google.com/p/redbridge/. RedBridge 具有以下特征:. 使用C+epoll 编写的Web Server,支持HTTP GET操作.

什么是Node?

- We_Get - 博客园新闻频道
译者按:前不久Oreilly出了一本小册子“What is Node?”,扼要的讲解了Node的身世和所适用的场景,作者文笔轻松流畅、内容充实,是非常难得的学习资料.   译文全文:http://jayli.github.com/whatisnode/index.html.   作者:Brett McLaughlin ,原文:What is Node?.

Node入门

- - CSDN博客编程语言推荐文章
作者:  Manuel Kiessling. 翻译:  goddyzhao &  GrayZhang &  MondayChen. 本书致力于教会你如何用Node.js来开发应用,过程中会传授你所有所需的“高级”JavaScript知识. 本书绝不是一本“Hello World”的教程. 你正在阅读的已经是本书的最终版.

浅析Hadoop Secondary NameNode,CheckPoint Node,Backup Node

- - CSDN博客云计算推荐文章
Hadoop SecondaryNameNode并不是Hadoop 第二个NameNode,它不提供NameNode服务,而仅仅是NameNode的一个工具. 这个工具帮助NameNode管理Metadata数据. NameNode的HDFS文件信息(即Metadata)记录在内存中,client的文件写操作直接修改内存中的Metadata,同时也会记录到硬盘的Edits文件,这是一个Log文件.

[译]什么是Node?

- blacktulip - Taobao UED Team
译者按:前不久Oreilly出了一本小册子“What is Node?”,扼要的讲解了Node的身世和所适用的场景,作者文笔轻松流畅、内容充实,是非常难得的学习资料. 译文全文:http://jayli.github.com/whatisnode/index.html. 作者:Brett McLaughlin ,原文:What is Node?.

用node作桌面开发

- InterMa - CNode社区
node的定位是,server-side javascript. 但程序员最爱做的事,就是把一个东西用在不该用的地方. 那么,可以把node用在桌面开发上吗. 把Javascript用在桌面开发上,早有先例,比如GTK+的gjs,还有Qt的QML(顺带一提,QML代表着桌面开发的另一个方向,a promising way),GNOME3中,也用javascript作为桌面插件的开发语言.

node js 断点调试

- - Web前端 - ITeye博客
大部分基于 Node.js 的应用都是运行在浏览器中的,. 例如强大的调试工具 node-inspector. node-inspector 是一个完全基于 Node.js 的开源在线调试工具,提供了强大的调试功能和友好. 的用户界面,它的使用方法十分简便. 首先,使用 npm install -g node-inspector 命令安装 node-inspector,然后在终.

Vercel 部署 Node 服务

- - 掘金 前端
之前在写 面试常客:HTTP 缓存时,曾经就强缓存和协商缓存写过两个demo,但缓存要在服务端做,只能贴上代码,不能在网页上感受(虽然我贴了gif). 笔者的所有 demo 例子都放在 github page 上,其特点是不需要服务器即可部署静态资源,但它不具备部署服务端应用能力. 最近笔者在了解 CI/CD 方面的知识点,想起了 Vercel,就想着能否将服务端应用架在 vercel 上呢.