From 4be4208278f02ab5cda38c516374dc449a3b2bb6 Mon Sep 17 00:00:00 2001 From: Miyamizu-MitsuhaSang <2510681107@qq.com> Date: Tue, 16 Sep 2025 11:02:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=8A=A8=E6=80=81=E7=BF=BB?= =?UTF-8?q?=E8=AF=91=E7=9A=84=E5=90=8E=E7=AB=AF=E4=BF=9D=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/translator.py | 42 +++++++++++++++++++++++++++++++++++++----- main.py | 2 +- requirements.txt | Bin 1556 -> 1590 bytes settings.py | 1 + 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/app/api/translator.py b/app/api/translator.py index 118422e..ac86675 100644 --- a/app/api/translator.py +++ b/app/api/translator.py @@ -1,12 +1,10 @@ -from typing import Tuple -from wsgiref import headers +from typing import Tuple, Dict +import aioredis import httpx import random import json -from hashlib import md5 -import requests from fastapi import APIRouter, Depends, HTTPException from app.models import User @@ -92,6 +90,31 @@ async def baidu_translation(query: str, from_lang: str, to_lang: str): return "\n".join([item["dst"] for item in data["trans_result"]]) +redis = aioredis.from_url("redis://localhost", encoding="utf-8", decode_responses=True) + + +async def rate_limiter( + user: Tuple[User, Dict] = Depends(get_current_user), + limit: int = 2, + window: int = 1 +): + """ + 限制每个 IP 在 window 秒内最多 limit 次请求 + """ + client_ip = user[0].id + key = f"rate limit {client_ip}" + + count = await redis.get(key) + + if count is None: + # 第一次请求 → 设置计数和过期时间 + await redis.set(key, 1, ex=window) + elif int(count) < limit: + await redis.incr(key) + else: + raise HTTPException(status_code=429, detail=f"Too many requests") + + @translator_router.post('/translate', response_model=TransResponse) async def translate( translate_request: TransRequest, @@ -105,12 +128,21 @@ async def translate( return TransResponse(translated_text=text) -@translator_router.post('/translate/debug') +@translator_router.post('/translate/debug', dependencies=[Depends(rate_limiter)]) async def test_translate( query: str, from_lang: str = "auto", to_lang: str = 'zh', admin_user: Tuple[User, dict] = Depends(is_admin_user) ): + """ + 尝试使用多次翻译请求接口,要求在前端监听输入在约300ms左右内保持不输入再传入, + 同时后端检查避免多次恶意访问 + :param query: 待翻译文本 + :param from_lang: 源语言,默认auto,百度API自动检测 + :param to_lang: 目标语言,不允许auto + :param admin_user: 测试接口,仅管理员权限可用 + :return: + """ raw = await baidu_translation(query, from_lang, to_lang) return TransResponse(translated_text=raw) diff --git a/main.py b/main.py index a90ca7f..4702de9 100644 --- a/main.py +++ b/main.py @@ -46,7 +46,7 @@ app.add_middleware( register_tortoise( app=app, - config=TORTOISE_ORM, + config=ONLINE_SETTINGS, ) app.include_router(users_router, tags=["User API"], prefix="/users") diff --git a/requirements.txt b/requirements.txt index 1145d40d7f9c2e40b58c023e08886973156280cf..d153277ddc1be2ad694a679a9b336fa09622bd8a 100644 GIT binary patch delta 45 ucmbQjvyDgP|Gx}|5+E#Ks9@k_;9^K*$YjW8C}K!uNCC2n!D1VkgxCNYXbJ@Y delta 11 ScmdnSGlhrg|G$kYLTmsWK?F|# diff --git a/settings.py b/settings.py index c9c455b..37fd448 100644 --- a/settings.py +++ b/settings.py @@ -47,6 +47,7 @@ class Settings(BaseSettings): SECRET_KEY: str BAIDU_APPID: str BAIDU_APPKEY: str + REDIS_URL: str class Config: env_file = '.env'