域名管理
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use think\Cache;
|
||||
use think\Exception;
|
||||
|
||||
/**
|
||||
* 域名检测频率限制
|
||||
* 每分钟最多 2 次,超限后冷却 120 秒
|
||||
*/
|
||||
class DomainDetectRateLimitService
|
||||
{
|
||||
/** 统计窗口(秒) */
|
||||
private const WINDOW_SECONDS = 60;
|
||||
|
||||
/** 窗口内最大检测次数 */
|
||||
private const MAX_ATTEMPTS = 2;
|
||||
|
||||
/** 超限后冷却时间(秒) */
|
||||
private const COOLDOWN_SECONDS = 120;
|
||||
|
||||
/**
|
||||
* 校验是否允许检测,不允许时抛出异常
|
||||
*
|
||||
* @param int $adminId 管理员 ID
|
||||
* @param int $domainId 域名记录 ID
|
||||
* @throws Exception
|
||||
*/
|
||||
public function assertCanDetect(int $adminId, int $domainId): void
|
||||
{
|
||||
$now = time();
|
||||
$baseKey = 'domain_detect:' . $adminId . ':' . $domainId;
|
||||
$cooldownKey = $baseKey . ':cooldown';
|
||||
$attemptsKey = $baseKey . ':attempts';
|
||||
|
||||
$cooldownUntil = (int)Cache::get($cooldownKey, 0);
|
||||
if ($cooldownUntil > $now) {
|
||||
$wait = $cooldownUntil - $now;
|
||||
throw new Exception(sprintf('检测过于频繁,请 %d 秒后再试', $wait));
|
||||
}
|
||||
|
||||
$timestamps = Cache::get($attemptsKey);
|
||||
if (!is_array($timestamps)) {
|
||||
$timestamps = [];
|
||||
}
|
||||
|
||||
$timestamps = array_values(array_filter($timestamps, static function ($ts) use ($now): bool {
|
||||
return is_int($ts) && ($now - $ts) < self::WINDOW_SECONDS;
|
||||
}));
|
||||
|
||||
if (count($timestamps) >= self::MAX_ATTEMPTS) {
|
||||
Cache::set($cooldownKey, $now + self::COOLDOWN_SECONDS, self::COOLDOWN_SECONDS);
|
||||
Cache::set($attemptsKey, $timestamps, self::WINDOW_SECONDS + self::COOLDOWN_SECONDS);
|
||||
throw new Exception(sprintf(
|
||||
'一分钟最多检测 %d 次,请 %d 秒后再试',
|
||||
self::MAX_ATTEMPTS,
|
||||
self::COOLDOWN_SECONDS
|
||||
));
|
||||
}
|
||||
|
||||
$timestamps[] = $now;
|
||||
Cache::set($attemptsKey, $timestamps, self::WINDOW_SECONDS + self::COOLDOWN_SECONDS);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user