Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

速率限制

启用 rate-limit Feature 可为 handler 应用命名的速率限制策略。支持 HTTP、WebSocket 和 TCP 传输层。

配置

#![allow(unused)]
fn main() {
use afast::{RateLimitConfig, RateLimitPolicy, RateLimitKey, Algorithm};

let app = AFast::new()
    .rate_limit(
        RateLimitConfig::new()
            .policy(RateLimitPolicy {
                id: "login".into(),
                max_requests: 5,
                window_secs: 60,
                key: RateLimitKey::Ip,
                algorithm: Algorithm::SlidingWindow,
            })
            .default_policy("global")
            .policy(RateLimitPolicy {
                id: "global".into(),
                max_requests: 100,
                window_secs: 1,
                key: RateLimitKey::Ip,
                algorithm: Algorithm::SlidingWindow,
            }),
    )
    .service(svc)
    .http("0.0.0.0:5000");
}

绑定 Handler

#![allow(unused)]
fn main() {
#[handler(rate_limit("login"), desc("User login"))]
async fn login(
    state: State<AppState>,
    req: Data<LoginRequest>,
) -> Result<LoginResponse> {
    // ...
}
}

没有 rate_limit 的 handler 自动使用 default_policy。如果未设置默认策略,则不受速率限制。

速率限制键

描述HTTPWebSocketTCP
Ip客户端 IP(支持 X-Forwarded-For
Header("name")HTTP 头值(如 API Key)✅ (握手时缓存)⏭ 跳过
Connection按连接(WS/TCP 消息速率)⏭ 跳过
Global共享全局计数器

存储后端

默认的 InMemoryStore 在进程内存中保存计数器。实现 RateLimitStore 可使用自定义后端(如 Redis):

#![allow(unused)]
fn main() {
use afast::RateLimitStore;

struct RedisStore { /* ... */ }

impl RateLimitStore for RedisStore {
    fn incr<'a>(&'a self, key: &'a str, ttl_secs: u64)
        -> Pin<Box<dyn Future<Output = u64> + Send + 'a>> { /* INCR + EXPIRE */ }
    fn get<'a>(&'a self, key: &'a str)
        -> Pin<Box<dyn Future<Output = u64> + Send + 'a>> { /* GET */ }
    fn set<'a>(&'a self, key: &'a str, value: u64, ttl_secs: u64)
        -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> { /* SET + EXPIRE */ }
    fn delete<'a>(&'a self, key: &'a str)
        -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> { /* DEL */ }
}
}

拒绝响应

  • HTTP: 状态码 429 Too Many Requests,响应体: {"code":-90012,"message":"Too many requests"}
  • WebSocket / TCP: 错误帧,错误码 -90012

可通过 RateLimitConfig::rejected_code()rejected_message() 自定义。

已复制到剪贴板!