diff --git a/server/app/api/cache/UserCache.php b/server/app/api/cache/UserCache.php index 91e4d93..fa95c09 100644 --- a/server/app/api/cache/UserCache.php +++ b/server/app/api/cache/UserCache.php @@ -226,4 +226,60 @@ class UserCache $key = self::sessionUsernamePrefix() . $username; return Cache::delete($key); } + + /** 玩家缓存 key 前缀(Token 中间件用,减少重复查库) */ + private static function playerCachePrefix(): string + { + return config('api.player_cache_prefix', 'api:player:'); + } + + private static function playerCacheTtl(): int + { + return (int) config('api.player_cache_ttl', 300); + } + + /** + * 按 username 缓存玩家信息(仅 id + username,供中间件注入 request->player 后使用) + * 登录/信息变更时需调用 deletePlayerByUsername 失效 + */ + public static function setPlayerByUsername(string $username, array $playerRow): bool + { + if ($username === '' || empty($playerRow)) { + return false; + } + $ttl = self::playerCacheTtl(); + if ($ttl <= 0) { + return true; + } + $key = self::playerCachePrefix() . $username; + return Cache::set($key, json_encode($playerRow), $ttl); + } + + /** 按 username 取缓存玩家,未命中返回 null */ + public static function getPlayerByUsername(string $username): ?array + { + if ($username === '') { + return null; + } + if (self::playerCacheTtl() <= 0) { + return null; + } + $key = self::playerCachePrefix() . $username; + $val = Cache::get($key); + if ($val === null || $val === '') { + return null; + } + $data = json_decode((string) $val, true); + return is_array($data) ? $data : null; + } + + /** 退出登录或玩家信息变更时删除玩家缓存 */ + public static function deletePlayerByUsername(string $username): bool + { + if ($username === '') { + return false; + } + $key = self::playerCachePrefix() . $username; + return Cache::delete($key); + } } diff --git a/server/app/api/controller/UserController.php b/server/app/api/controller/UserController.php index ddfc8ca..4898eaf 100644 --- a/server/app/api/controller/UserController.php +++ b/server/app/api/controller/UserController.php @@ -81,6 +81,7 @@ class UserController extends OpenController return $this->fail('token 无效', ReturnCode::TOKEN_INVALID); } UserCache::deleteSessionByUsername($username); + UserCache::deletePlayerByUsername($username); return $this->success('已退出登录'); } diff --git a/server/app/api/logic/UserLogic.php b/server/app/api/logic/UserLogic.php index 6d23e46..b728241 100644 --- a/server/app/api/logic/UserLogic.php +++ b/server/app/api/logic/UserLogic.php @@ -84,6 +84,7 @@ class UserLogic $userArr = $player->hidden(['password'])->toArray(); UserCache::setUser((int) $player->id, $userArr); + UserCache::setPlayerByUsername($username, $userArr); $baseUrl = rtrim(config('api.login_url_base', 'https://127.0.0.1:6777'), '/'); $lang = in_array($lang, ['chs', 'en'], true) ? $lang : 'chs'; diff --git a/server/app/api/middleware/TokenMiddleware.php b/server/app/api/middleware/TokenMiddleware.php index 37f18db..d948e40 100644 --- a/server/app/api/middleware/TokenMiddleware.php +++ b/server/app/api/middleware/TokenMiddleware.php @@ -66,10 +66,19 @@ class TokenMiddleware implements MiddlewareInterface throw new ApiException('请重新登录(当前账号已在其他处登录)', ReturnCode::TOKEN_INVALID); } - $player = DicePlayer::where('username', $username)->find(); - if (!$player) { - UserCache::deleteSessionByUsername($username); - throw new ApiException('请重新登录', ReturnCode::TOKEN_INVALID); + // 优先从 Redis 缓存取玩家,避免每次请求都查库 + $player = null; + $cached = UserCache::getPlayerByUsername($username); + if ($cached !== null && isset($cached['id'])) { + $player = (new DicePlayer())->data($cached, true); + } + if ($player === null) { + $player = DicePlayer::where('username', $username)->find(); + if (!$player) { + UserCache::deleteSessionByUsername($username); + throw new ApiException('请重新登录', ReturnCode::TOKEN_INVALID); + } + UserCache::setPlayerByUsername($username, $player->hidden(['password'])->toArray()); } $request->player_id = (int) $player->id; $request->player = $player; diff --git a/server/config/api.php b/server/config/api.php index 3abb2e2..2a0909d 100644 --- a/server/config/api.php +++ b/server/config/api.php @@ -27,4 +27,7 @@ return [ 'user_cache_prefix' => env('API_USER_CACHE_PREFIX', 'api:user:'), // 用户信息加密密钥(用于 Redis 中 value 的加密),建议 32 位 'user_encrypt_key' => env('API_USER_ENCRYPT_KEY', 'dafuweng_api_user_cache_key_32'), + // 玩家信息按 username 缓存(Token 中间件用),0 表示不缓存 + 'player_cache_ttl' => (int) env('API_PLAYER_CACHE_TTL', 300), + 'player_cache_prefix' => env('API_PLAYER_CACHE_PREFIX', 'api:player:'), ]; diff --git a/server/config/app.php b/server/config/app.php index f26e358..5c0e571 100644 --- a/server/config/app.php +++ b/server/config/app.php @@ -15,7 +15,8 @@ use support\Request; return [ - 'debug' => true, + // 生产环境务必设为 false,减少 I/O 与堆栈输出,提升接口响应 + 'debug' => env('APP_DEBUG', false), 'error_reporting' => E_ALL, 'default_timezone' => 'Asia/Shanghai', 'request_class' => Request::class, diff --git a/server/config/database.php b/server/config/database.php index 122bb22..f455467 100644 --- a/server/config/database.php +++ b/server/config/database.php @@ -18,10 +18,10 @@ return [ PDO::ATTR_EMULATE_PREPARES => false, // Must be false for Swoole and Swow drivers. ], 'pool' => [ - 'max_connections' => 5, - 'min_connections' => 1, - 'wait_timeout' => 3, - 'idle_timeout' => 60, + 'max_connections' => (int) env('DB_POOL_MAX', 20), + 'min_connections' => (int) env('DB_POOL_MIN', 2), + 'wait_timeout' => (float) env('DB_POOL_WAIT_TIMEOUT', 1.0), + 'idle_timeout' => (int) env('DB_POOL_IDLE_TIMEOUT', 60), 'heartbeat_interval' => 50, ], ], diff --git a/server/config/log.php b/server/config/log.php index 7f05de5..46d7992 100644 --- a/server/config/log.php +++ b/server/config/log.php @@ -20,7 +20,7 @@ return [ 'constructor' => [ runtime_path() . '/logs/webman.log', 7, //$maxFiles - Monolog\Logger::DEBUG, + env('LOG_LEVEL', Monolog\Logger::INFO), ], 'formatter' => [ 'class' => Monolog\Formatter\LineFormatter::class, diff --git a/server/config/redis.php b/server/config/redis.php index 5b4b993..53655ef 100644 --- a/server/config/redis.php +++ b/server/config/redis.php @@ -7,9 +7,9 @@ return [ 'port' => env('REDIS_PORT', 6379), 'database' => env('REDIS_DB', 0), 'pool' => [ - 'max_connections' => 5, - 'min_connections' => 1, - 'wait_timeout' => 3, + 'max_connections' => (int) env('REDIS_POOL_MAX', 20), + 'min_connections' => (int) env('REDIS_POOL_MIN', 2), + 'wait_timeout' => (float) env('REDIS_POOL_WAIT_TIMEOUT', 1.0), 'idle_timeout' => 60, 'heartbeat_interval' => 50, ], diff --git a/server/config/think-cache.php b/server/config/think-cache.php index e26cf48..4cde933 100644 --- a/server/config/think-cache.php +++ b/server/config/think-cache.php @@ -24,13 +24,13 @@ return [ 'tag_expire' => 86400 * 30, // 缓存标签前缀 'tag_prefix' => 'tag:', - // 连接池配置 + // 连接池配置(与 redis.php 对齐,生产可调大以减少等待) 'pool' => [ - 'max_connections' => 5, // 最大连接数 - 'min_connections' => 1, // 最小连接数 - 'wait_timeout' => 3, // 从连接池获取连接等待超时时间 - 'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收 - 'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒 + 'max_connections' => (int) env('REDIS_POOL_MAX', 20), + 'min_connections' => (int) env('REDIS_POOL_MIN', 2), + 'wait_timeout' => (float) env('REDIS_POOL_WAIT_TIMEOUT', 1.0), + 'idle_timeout' => 60, + 'heartbeat_interval' => 50, ], ], // 文件缓存 diff --git a/server/config/think-orm.php b/server/config/think-orm.php index 40d208f..a106c12 100644 --- a/server/config/think-orm.php +++ b/server/config/think-orm.php @@ -18,8 +18,7 @@ return [ 'hostport' => env('DB_PORT', 3306), // 数据库连接参数 'params' => [ - // 连接超时3秒 - \PDO::ATTR_TIMEOUT => 3, + \PDO::ATTR_TIMEOUT => (int) env('DB_CONNECT_TIMEOUT', 2), ], // 数据库编码默认采用utf8 'charset' => 'utf8', @@ -29,13 +28,13 @@ return [ 'break_reconnect' => true, // 自定义分页类 'bootstrap' => '', - // 连接池配置 + // 连接池配置(与 database.php 对齐) 'pool' => [ - 'max_connections' => 5, // 最大连接数 - 'min_connections' => 1, // 最小连接数 - 'wait_timeout' => 3, // 从连接池获取连接等待超时时间 - 'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收 - 'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒 + 'max_connections' => (int) env('DB_POOL_MAX', 20), + 'min_connections' => (int) env('DB_POOL_MIN', 2), + 'wait_timeout' => (float) env('DB_POOL_WAIT_TIMEOUT', 1.0), + 'idle_timeout' => (int) env('DB_POOL_IDLE_TIMEOUT', 60), + 'heartbeat_interval' => 50, ], ], ], diff --git a/server/plugin/saiadmin/config/middleware.php b/server/plugin/saiadmin/config/middleware.php index b63eaaf..61b9c66 100644 --- a/server/plugin/saiadmin/config/middleware.php +++ b/server/plugin/saiadmin/config/middleware.php @@ -4,8 +4,9 @@ use plugin\saiadmin\app\middleware\SystemLog; use plugin\saiadmin\app\middleware\CheckLogin; use plugin\saiadmin\app\middleware\CheckAuth; +// 仅对 /core 后台路由生效,避免 /api 请求经过登录/权限/操作日志中间件,提升接口响应 return [ - '' => [ + 'core' => [ CheckLogin::class, CheckAuth::class, SystemLog::class,