4 个版本
0.3.1 | 2021 年 1 月 17 日 |
---|---|
0.3.0 | 2020 年 12 月 28 日 |
0.2.1 | 2020 年 2 月 7 日 |
0.2.0 | 2020 年 2 月 7 日 |
0.1.0 |
|
#677 在 HTTP 服务器 中
每月 506 次下载
在 2 crates 中使用
68KB
1K SLoC
actix-ratelimit
actix-web 的速率限制中间件框架
此 crate 提供了一个基于 actor 模型的异步并发速率限制中间件,可以围绕 Actix 应用程序进行封装。中间件包含一个用于识别客户端请求的存储。
请在此处查看 文档。
欢迎评论、建议和批评!
用法
将以下内容添加到您的 Cargo.toml 中
[dependencies]
actix-ratelimit = "0.3.1"
版本 0.3.*
支持 actix-web v3。如果您正在使用 actix-web v2,请考虑使用版本 0.2.*
。
最小示例
use actix_web::{web, App, HttpRequest, HttpServer, Responder};
use actix_ratelimit::{RateLimiter, MemoryStore, MemoryStoreActor};
use std::time::Duration;
async fn greet(req: HttpRequest) -> impl Responder{
let name = req.match_info().get("name").unwrap_or("World!");
format!("Hello {}!", &name)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// Initialize store
let store = MemoryStore::new();
HttpServer::new(move ||{
App::new()
// Register the middleware
// which allows for a maximum of
// 100 requests per minute per client
// based on IP address
.wrap(
RateLimiter::new(
MemoryStoreActor::from(store.clone()).start())
.with_interval(Duration::from_secs(60))
.with_max_requests(100)
)
.route("/", web::get().to(greet))
.route("/{name}", web::get().to(greet))
})
.bind("127.0.0.1:8000")?
.run()
.await
}
发送请求返回包含速率限制头部的响应
$ curl -i "https://127.0.0.1:8000/"
HTTP/1.1 200 OK
content-length: 13
content-type: text/plain; charset=utf-8
x-ratelimit-remaining: 99
x-ratelimit-reset: 52
x-ratelimit-limit: 100
date: Tue, 04 Feb 2020 21:53:27 GMT
Hello World!
超过限制将返回 HTTP 429 错误代码。
存储
存储 是一种数据结构、数据库连接或任何可以用于存储与 客户端 关联的 速率限制 数据的东西。一个对存储进行操作的 存储 actor 负责执行所有类型的操作(SET、GET、DEL 等)。重要的是要注意,有多个存储 actor 在单个存储上操作。
功能列表
memory
(基于并发 hashmap 的内存存储)redis-store
(基于 redis-rs)memcached
(基于 r2d2-memcache,见下文开发者注释)
实现自己的存储
要实现自己的存储,您必须实现一个可以处理Actor,它能够处理ActorMessage类型并返回ActorResponse类型。有关更多详细信息和一个基本示例,请查看模块级别文档。
开发者注意
- 默认情况下,所有功能均已启用。要使用特定功能,例如redis,请在Cargo.toml中添加以下内容:
[dependencies]
actix-ratelimit = {version = "0.3.1", default-features = false, features = ["redis-store"]}
- 默认情况下,客户端的IP地址用作标识符,可以使用ServiceRequest实例进行自定义。例如,使用API密钥头部来识别客户端。
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// Initialize store
let store = MemoryStore::new();
HttpServer::new(move ||{
App::new()
.wrap(
RateLimiter::new(
MemoryStoreActor::from(store.clone()).start())
.with_interval(Duration::from_secs(60))
.with_max_requests(100)
.with_identifier(|req| {
let key = req.headers().get("x-api-key").unwrap();
let key = key.to_str().unwrap();
Ok(key.to_string())
})
)
.route("/", web::get().to(greet))
.route("/{name}", web::get().to(greet))
})
.bind("127.0.0.1:8000")?
.run()
.await
}
-
由于尚无法在memcache中本地获取键的TTL,因此memcache存储使用单独的键来跟踪过期时间。这意味着与redis存储相比,memcache存储将使用两倍的键数。如果还有更好的方法,请考虑提出问题!
-
在创建HttpServer实例之前初始化存储非常重要,否则将为每个web worker创建一个存储。这可能导致不稳定和不一致!例如,以下方式初始化您的应用程序将创建多个存储:
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(move ||{
App::new()
.wrap(
RateLimiter::new(
MemoryStoreActor::from(MemoryStore::new()).start())
.with_interval(Duration::from_secs(60))
.with_max_requests(100)
)
.route("/", web::get().to(greet))
.route("/{name}", web::get().to(greet))
})
.bind("127.0.0.1:8000")?
.run()
.await
}
- 要启用跨多个Web应用程序实例(负载均衡器后面的多个http服务器)的速率限制,请考虑使用由AWS、Azure等流行的云服务支持的名为“会话粘性”的功能。
状态
该项目尚未达到v1.0,因此在此期间可能会出现一些不稳定性和破坏性更改。
如果遇到任何问题,您可以使用问题跟踪器。
许可证
本项目采用MIT许可证。
许可证:MIT
依赖项
~24–34MB
~597K SLoC