68 lines
1.7 KiB
PHP
68 lines
1.7 KiB
PHP
<?php
|
|
|
|
namespace app\middleware;
|
|
|
|
use think\facade\Cache;
|
|
use think\Request;
|
|
|
|
class RateLimit
|
|
{
|
|
public function handle(Request $request, \Closure $next)
|
|
{
|
|
$authContext = $request->authContext ?? null;
|
|
if (!$authContext) {
|
|
return $next($request);
|
|
}
|
|
|
|
$apiKeyId = $authContext['api_key_id'];
|
|
$limitPerMinute = $authContext['rate_limit_per_minute'] ?? 60;
|
|
$limitPerDay = $authContext['rate_limit_per_day'] ?? 5000;
|
|
|
|
$minuteKey = 'rate_limit:minute:' . $apiKeyId;
|
|
$dayKey = 'rate_limit:day:' . $apiKeyId . ':' . date('Ymd');
|
|
|
|
$minuteCount = $this->getCount($minuteKey);
|
|
if ($minuteCount >= $limitPerMinute) {
|
|
return json([
|
|
'code' => 429,
|
|
'msg' => '请求过于频繁,请稍后再试'
|
|
], 429);
|
|
}
|
|
|
|
$dayCount = $this->getCount($dayKey);
|
|
if ($dayCount >= $limitPerDay) {
|
|
return json([
|
|
'code' => 429,
|
|
'msg' => '今日请求次数已达上限'
|
|
], 429);
|
|
}
|
|
|
|
$this->increment($minuteKey, 60);
|
|
$this->increment($dayKey, 86400);
|
|
|
|
return $next($request);
|
|
}
|
|
|
|
private function getCount($key)
|
|
{
|
|
try {
|
|
$value = Cache::get($key);
|
|
return $value !== false ? (int)$value : 0;
|
|
} catch (\Exception $e) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private function increment($key, $ttl)
|
|
{
|
|
try {
|
|
$current = $this->getCount($key);
|
|
$newValue = $current + 1;
|
|
Cache::set($key, $newValue, $ttl);
|
|
return $newValue;
|
|
} catch (\Exception $e) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|