来源:https://codeburst.io/
作者:Joyce Lin
速率限制可以保护和提高基于API的服务的可用性。如果你正在与一个API对话,并收到HTTP 429 Too Many Requests的响应状态码,说明你已经被速率限制了。这意味着你超出了给定时间内允许的请求数量,你需要做的就是放慢脚步,稍等片刻,然后再试一次。
为什么要速率限制?
当你考虑限制你自己的基于API的服务时,你需要在用户体验、安全性和性能之间进行权衡。
控制数据流的最常见原因是保持基于API的服务的可用性。但也有安全方面的好处,一次无意或有意的入站流量激增,就会占用宝贵的资源,影响其他用户的可用性。
通过控制传入请求的速率,你可以:
如何实施限速?
速率限制可以在客户端级别,应用程序级别,基础架构级别或介于两者之间的任何位置实现。有几种方法可以控制API服务的入站流量:
你可以使用这些速率限制中的任何一种(甚至组合使用)。
无论你选择如何实现,速率限制的目标都是建立一个检查点,该检查点拒绝或通过访问你的资源的请求。许多编程语言和框架都有实现这一点的内置功能或中间件,还有各种速率限制算法的选项。
这是使用Node和Redis制作自己的速率限制器的一种方法:
💻 在GitHub[1]上查看代码示例。
在开始之前,请确保已在计算机上安装了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实施速率限制也非常简单。
下图所示的限速算法是一个滑动窗口计数器的例子。一个用户如果提交的调用数量适中,或者随着时间的推移将它们分隔开,就永远不会达到速率限制。超过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的速率限制器的简单示例,这只是开始。有一堆策略和工具可以用来架构和实现你的速率限制。而且还有其他的增强功能可以通过这个例子来探索,比如:
请记住,当你研究API限制时,你是在性能、安全性和用户体验之间进行权衡。你理想的速率限制解决方案将随着时间的推移而改变,同时也会考虑到这些因素。
本文转载自微信公众号「前端全栈开发者」,可以通过以下二维码关注。转载本文请联系前端全栈开发者公众号。
今天的CIO会感觉自己就像是马戏团的表演者,同时处理多个项目,还要确保没有一个...
早咯~ 转眼九月快临近尾声,新的一周又开始啦,照例来一份TOP云(zuntop.com) ...
很多人在选择VPS时都希望能够找到一个好的VPS,只不过在选择 美国私人vps https:...
爱因斯坦在给他的第一个传记作者卡尔-塞利格的信中说:我没有什么特殊的才能,我...
网络攻击一直以来都是互联网行业的痛点,目前随着中小型互联网企业数量的迅速增...
Julius Neudorfer是北美接入技术有限公司(NAAT)的创始人和首席技术官。北美接入...
麻省理工学院信息系统研究中心首席研究科学家Jeanne Ross在企业架构研究方面具有...
1.如果眼泪可以承载悲哀,我宁愿它泛滥成海。 2.这辈子最对不起的就是自己的心...
随着越来越多的组织转向数字化转型,他们正在迅速采用行业领先的技术。这通常从...
在如今的生活中,游戏行业是受到网络攻击最为明显的行业,所以很多游戏的企业都...