FastAPI 和 SlowAPI 限制所有“path/*”下的请求

FastAPI and SlowAPI limit request under all “path/*”

我在使用 SlowAPI 时遇到问题。所有的请求都是按照中间件来限制的,但是我没办法把所有的请求都限制在/schools/

这个路径下

我的代码:

from fastapi import FastAPI, Request, Response, status
from fastapi.middleware.cors import CORSMiddleware
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from slowapi.middleware import SlowAPIMiddleware

limiter = Limiter(key_func=get_remote_address, default_limits=["2/5seconds"])
app = FastAPI()
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

origins = ["http://127.0.0.1/", "http://localhost", "http://192.168.1.75"] ## CORS

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
app.add_middleware(SlowAPIMiddleware) ## Rate-limit all request

@app.get('/schools/{regione}/{provincia}/{comune}')
def search_school(request: Request, response: Response, regione: str, provincia: str, comune: str):
        return {"message": 'No schools found!', "status": 'error', "code": 200} ## Or if found return schools informations

@app.get('/testpath/{regione}') ## Works with one path. If I add "provincia" and "comune" non work
def search_school(request: Request, response: Response, regione: str, provincia: str, comune: str):
        return {"message": 'No schools found!', "status": 'error', "code": 200} ## Or if found return schools informations

当我使用 jQuery 向 /schools/{region}/{province}/{city} 发送请求时,整个 url 受到限制,因此如果我更改地区或省份,限制将被重置。如何让自己应用 /schools/*

的设置

示例:

每 5 秒请求 2 次

如果我向 apiURL+/schools/Lombardy/Milan/Milan 发送请求,限制会增加 1,如果我在第三次发出另一个 2 请求,我会被阻止。

但是如果我没有进入同一个域,而是更改了城市 (apiURL+/schools/Sicily/Palermo/Palermo),限制将重置并且 returns 为 1

选项 1

实例化Limiterclass时定义application_limits,如下图。根据 documentation

application_limits: a variable list of strings or callables returning strings for limits that are applied to the entire application (i.e., a shared limit for all routes)

因此,以下将对所有 /schools/* 路由以及您的应用程序中可能存在的任何其他路由(例如 /testpath/*/some-other-route/、依此类推),这意味着每个客户端每 5 秒只能通过两个请求(无论他们调用的端点如何)。

limiter = Limiter(key_func=get_remote_address, application_limits=["2/5seconds"])

选项 2

使用 shared_limit 仅将共享限制应用于您希望的端点。根据 documentation:

shared_limit: Decorator to be applied to multiple routes sharing the same rate limit.

因此,以下将仅对 /schools/* 条路线应用共享限制。

limiter = Limiter(key_func=get_remote_address, default_limits=["2/5seconds"])

@app.get('/schools/{regione}/{provincia}/{comune}')
@limiter.shared_limit(limit_value="2/5seconds", scope="schools") 
def search_school(request: Request, response: Response, regione: str, provincia: str, comune: str):
        return {"message": 'No schools found!', "status": 'error', "code": 200}