当前位置: 首页 > 后端技术 > Node.js

APIRateLimitingwithNodeandRedis(转载)

时间:2023-04-03 23:51:46 Node.js

Ratelimiting可以保护和提高基于API的服务的可用性。如果您正在与API对话并收到HTTP429TooManyRequests响应状态代码,则说明您的速率受到限制。这意味着您超出了给定时间内允许的请求数量。您需要做的就是放慢速度,稍等片刻,然后重试。为什么要限速?当您考虑限制自己的基于API的服务时,您需要在用户体验、安全性和性能之间做出权衡。控制数据流的最常见原因是维护基于API的服务的可用性。但也有安全方面的好处,因为入站流量的一次无意或有意激增可能会占用宝贵的资源并影响其他用户的可用性。通过控制传入请求的速率,您可以:确保服务和资源不会“不堪重负”。减轻暴力攻击防止分布式拒绝服务(DDOS)攻击如何实施速率限制?速率限制可以在客户端级别、应用程序级别、基础架构级别或两者之间的任何位置实施。有几种方法可以控制API服务的入站流量:每个用户:跟踪用户使用API密钥、访问令牌或IP地址进行的调用从地理上讲:例如,在一天中的高峰时段降低每个地理区域的费率限制每个服务器:如果您有多个服务器处理对您的API的不同调用,您可以对访问更昂贵的资源实施更严格的速率限制。您可以使用这些速率限制中的任何一个(甚至组合)。无论您选择如何实施它,速率限制的目标都是建立一个检查点,该检查点拒绝或传递访问您的资源的请求。许多编程语言和框架都有内置的函数或中间件来实现这一点,并且有各种速率限制算法的选项。这是使用Node和Redis制作您自己的速率限制器的一种方法:查看GitHub上的代码示例。在开始之前,请确保您的计算机上安装了Node和Redis。第1步:构建Node应用程序从命令行设置新的Node应用程序。通过CLI提示,或通过添加--yes标志接受默认选项。如果在项目设置期间接受了默认选项,则$npminit--yes会为入口点创建一个名为index.js的文件。$touchindex.js安装Expressweb框架,然后在index.js中初始化服务器。constexpress=require('express')constapp=express()constport=process.env.PORT||3000app.get('/',(req,res)=>res.send('HelloWorld!'))app.listen(port,()=>console.log(`示例应用程序在http://localhost监听:${port}`))从命令行启动服务器。$nodeindex.js回到index.js,创建一个路由,首先检查速率限制,然后如果用户没有超过限制则允许访问资源。app.post('/',async(req,res)=>{asyncfunctionisOverLimit(ip){//定义}//检查速率限制letoverLimit=awaitisOverLimit(req.ip)if(overLimit){res.status(429).send('Toomanyrequests-tryagainlater')return}//允许访问资源res.send("Accessedthepreciousresources!")})在下一步中我们将定义速率限制器函数是OverLimit。第2步:使用Redis添加速率限制器Redis是一个内存中的键值数据库,因此它可以非常快速地检索数据。使用Redis实现速率限制也非常简单。存储一个密钥,例如用户的IP地址。在指定的时间段后增加从该IPExpire记录发出的调用次数下图所示的速率限制算法是一个滑动窗口计数器的示例。如果用户提交适度数量的调用,或者随着时间的推移将它们间隔开,则用户永远不会达到速率限制。在10秒窗口内超过最大请求的用户必须等待足够的时间来恢复他们的请求。从命令行为Node安装名为ioredis的Redis客户端。$npminstallioredis在本地启动Redis服务器。$redis-server然后在index.js中请求并初始化Redis客户端。constredis=require('ioredis')constclient=redis.createClient({port:process.env.REDIS_PORT||6379,host:process.env.REDIS_HOST||'localhost',})client.on('connect',function(){console.log('connected');});定义我们上一步写的isOverLimit函数,根据Redis的这种模式,根据IP保存一个计数器。asyncfunctionisOverLimit(ip){letrestry{res=awaitclient.incr(ip)}catch(err){console.error('isOverLimit:couldnotincrementkey')throwerr}console.log(`${ip}有值:${res}`)if(res>10){returntrue}client.expire(ip,10)}这是速率??限制器。当用户调用API时,我们检查Redis以查看用户是否超过限制。如果是这样,API将立即返回HTTP429状态代码和消息Toomanyrequests—tryagainlater。如果用户在限制范围内,我们将继续执行下一个代码块,在该代码块中我们可以允许访问受保护的资源(例如数据库)。在速率限制检查期间,我们在Redis中找到用户的记录并增加其请求计数,如果Redis中没有该用户的记录,那么我们将创建一个新记录。最后,每条记录将在最近一次活动后的10秒内过期。在下一步中,确保我们的限速器正常运行。第3步:在Postman中测试保存更改并重新启动服务器。我们将使用Postman向我们的API服务器发送POST请求,该服务器在本地运行在http://localhost:3000。继续快速连续发送请求以达到您的速率限制。关于速率限制的最终想法这是Node和Redis速率限制器的一个简单示例,而这仅仅是个开始。您可以使用多种策略和工具来设计和实施速率限制。并且可以通过此示例探索其他增强功能,例如:在响应文本中或作为Retry-after标头,让用户知道在重试之前他们应该等待多长时间记录达到速率限制的请求以了解用户行为并警告试图使用其他速率限制算法或其他中间件的恶意攻击请记住,当您研究API节流时,您是在性能、安全性和用户体验之间进行权衡。考虑到这些因素,您理想的速率限制解决方案会随着时间而改变。