#rate-limiting #actix-web #middleware #actor-model #web-apps #actix

actix-ratelimit

actix-web 的速率限制中间件框架

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 2020 年 1 月 17 日

#677HTTP 服务器

Download history 123/week @ 2024-02-27 52/week @ 2024-03-05 61/week @ 2024-03-12 72/week @ 2024-03-19 57/week @ 2024-03-26 100/week @ 2024-04-02 164/week @ 2024-04-09 192/week @ 2024-04-16 193/week @ 2024-04-23 55/week @ 2024-04-30 47/week @ 2024-05-07 34/week @ 2024-05-14 124/week @ 2024-05-21 195/week @ 2024-05-28 63/week @ 2024-06-04 118/week @ 2024-06-11

每月 506 次下载
2 crates 中使用

MIT 许可证

68KB
1K SLoC

Travis (.org) Crates.io Crates.io

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