优化性能
This commit is contained in:
56
server/app/api/cache/UserCache.php
vendored
56
server/app/api/cache/UserCache.php
vendored
@@ -226,4 +226,60 @@ class UserCache
|
|||||||
$key = self::sessionUsernamePrefix() . $username;
|
$key = self::sessionUsernamePrefix() . $username;
|
||||||
return Cache::delete($key);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ class UserController extends OpenController
|
|||||||
return $this->fail('token 无效', ReturnCode::TOKEN_INVALID);
|
return $this->fail('token 无效', ReturnCode::TOKEN_INVALID);
|
||||||
}
|
}
|
||||||
UserCache::deleteSessionByUsername($username);
|
UserCache::deleteSessionByUsername($username);
|
||||||
|
UserCache::deletePlayerByUsername($username);
|
||||||
return $this->success('已退出登录');
|
return $this->success('已退出登录');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ class UserLogic
|
|||||||
|
|
||||||
$userArr = $player->hidden(['password'])->toArray();
|
$userArr = $player->hidden(['password'])->toArray();
|
||||||
UserCache::setUser((int) $player->id, $userArr);
|
UserCache::setUser((int) $player->id, $userArr);
|
||||||
|
UserCache::setPlayerByUsername($username, $userArr);
|
||||||
|
|
||||||
$baseUrl = rtrim(config('api.login_url_base', 'https://127.0.0.1:6777'), '/');
|
$baseUrl = rtrim(config('api.login_url_base', 'https://127.0.0.1:6777'), '/');
|
||||||
$lang = in_array($lang, ['chs', 'en'], true) ? $lang : 'chs';
|
$lang = in_array($lang, ['chs', 'en'], true) ? $lang : 'chs';
|
||||||
|
|||||||
@@ -66,11 +66,20 @@ class TokenMiddleware implements MiddlewareInterface
|
|||||||
throw new ApiException('请重新登录(当前账号已在其他处登录)', ReturnCode::TOKEN_INVALID);
|
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();
|
$player = DicePlayer::where('username', $username)->find();
|
||||||
if (!$player) {
|
if (!$player) {
|
||||||
UserCache::deleteSessionByUsername($username);
|
UserCache::deleteSessionByUsername($username);
|
||||||
throw new ApiException('请重新登录', ReturnCode::TOKEN_INVALID);
|
throw new ApiException('请重新登录', ReturnCode::TOKEN_INVALID);
|
||||||
}
|
}
|
||||||
|
UserCache::setPlayerByUsername($username, $player->hidden(['password'])->toArray());
|
||||||
|
}
|
||||||
$request->player_id = (int) $player->id;
|
$request->player_id = (int) $player->id;
|
||||||
$request->player = $player;
|
$request->player = $player;
|
||||||
return $handler($request);
|
return $handler($request);
|
||||||
|
|||||||
@@ -27,4 +27,7 @@ return [
|
|||||||
'user_cache_prefix' => env('API_USER_CACHE_PREFIX', 'api:user:'),
|
'user_cache_prefix' => env('API_USER_CACHE_PREFIX', 'api:user:'),
|
||||||
// 用户信息加密密钥(用于 Redis 中 value 的加密),建议 32 位
|
// 用户信息加密密钥(用于 Redis 中 value 的加密),建议 32 位
|
||||||
'user_encrypt_key' => env('API_USER_ENCRYPT_KEY', 'dafuweng_api_user_cache_key_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:'),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
use support\Request;
|
use support\Request;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'debug' => true,
|
// 生产环境务必设为 false,减少 I/O 与堆栈输出,提升接口响应
|
||||||
|
'debug' => env('APP_DEBUG', false),
|
||||||
'error_reporting' => E_ALL,
|
'error_reporting' => E_ALL,
|
||||||
'default_timezone' => 'Asia/Shanghai',
|
'default_timezone' => 'Asia/Shanghai',
|
||||||
'request_class' => Request::class,
|
'request_class' => Request::class,
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ return [
|
|||||||
PDO::ATTR_EMULATE_PREPARES => false, // Must be false for Swoole and Swow drivers.
|
PDO::ATTR_EMULATE_PREPARES => false, // Must be false for Swoole and Swow drivers.
|
||||||
],
|
],
|
||||||
'pool' => [
|
'pool' => [
|
||||||
'max_connections' => 5,
|
'max_connections' => (int) env('DB_POOL_MAX', 20),
|
||||||
'min_connections' => 1,
|
'min_connections' => (int) env('DB_POOL_MIN', 2),
|
||||||
'wait_timeout' => 3,
|
'wait_timeout' => (float) env('DB_POOL_WAIT_TIMEOUT', 1.0),
|
||||||
'idle_timeout' => 60,
|
'idle_timeout' => (int) env('DB_POOL_IDLE_TIMEOUT', 60),
|
||||||
'heartbeat_interval' => 50,
|
'heartbeat_interval' => 50,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ return [
|
|||||||
'constructor' => [
|
'constructor' => [
|
||||||
runtime_path() . '/logs/webman.log',
|
runtime_path() . '/logs/webman.log',
|
||||||
7, //$maxFiles
|
7, //$maxFiles
|
||||||
Monolog\Logger::DEBUG,
|
env('LOG_LEVEL', Monolog\Logger::INFO),
|
||||||
],
|
],
|
||||||
'formatter' => [
|
'formatter' => [
|
||||||
'class' => Monolog\Formatter\LineFormatter::class,
|
'class' => Monolog\Formatter\LineFormatter::class,
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ return [
|
|||||||
'port' => env('REDIS_PORT', 6379),
|
'port' => env('REDIS_PORT', 6379),
|
||||||
'database' => env('REDIS_DB', 0),
|
'database' => env('REDIS_DB', 0),
|
||||||
'pool' => [
|
'pool' => [
|
||||||
'max_connections' => 5,
|
'max_connections' => (int) env('REDIS_POOL_MAX', 20),
|
||||||
'min_connections' => 1,
|
'min_connections' => (int) env('REDIS_POOL_MIN', 2),
|
||||||
'wait_timeout' => 3,
|
'wait_timeout' => (float) env('REDIS_POOL_WAIT_TIMEOUT', 1.0),
|
||||||
'idle_timeout' => 60,
|
'idle_timeout' => 60,
|
||||||
'heartbeat_interval' => 50,
|
'heartbeat_interval' => 50,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ return [
|
|||||||
'tag_expire' => 86400 * 30,
|
'tag_expire' => 86400 * 30,
|
||||||
// 缓存标签前缀
|
// 缓存标签前缀
|
||||||
'tag_prefix' => 'tag:',
|
'tag_prefix' => 'tag:',
|
||||||
// 连接池配置
|
// 连接池配置(与 redis.php 对齐,生产可调大以减少等待)
|
||||||
'pool' => [
|
'pool' => [
|
||||||
'max_connections' => 5, // 最大连接数
|
'max_connections' => (int) env('REDIS_POOL_MAX', 20),
|
||||||
'min_connections' => 1, // 最小连接数
|
'min_connections' => (int) env('REDIS_POOL_MIN', 2),
|
||||||
'wait_timeout' => 3, // 从连接池获取连接等待超时时间
|
'wait_timeout' => (float) env('REDIS_POOL_WAIT_TIMEOUT', 1.0),
|
||||||
'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收
|
'idle_timeout' => 60,
|
||||||
'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒
|
'heartbeat_interval' => 50,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
// 文件缓存
|
// 文件缓存
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ return [
|
|||||||
'hostport' => env('DB_PORT', 3306),
|
'hostport' => env('DB_PORT', 3306),
|
||||||
// 数据库连接参数
|
// 数据库连接参数
|
||||||
'params' => [
|
'params' => [
|
||||||
// 连接超时3秒
|
\PDO::ATTR_TIMEOUT => (int) env('DB_CONNECT_TIMEOUT', 2),
|
||||||
\PDO::ATTR_TIMEOUT => 3,
|
|
||||||
],
|
],
|
||||||
// 数据库编码默认采用utf8
|
// 数据库编码默认采用utf8
|
||||||
'charset' => 'utf8',
|
'charset' => 'utf8',
|
||||||
@@ -29,13 +28,13 @@ return [
|
|||||||
'break_reconnect' => true,
|
'break_reconnect' => true,
|
||||||
// 自定义分页类
|
// 自定义分页类
|
||||||
'bootstrap' => '',
|
'bootstrap' => '',
|
||||||
// 连接池配置
|
// 连接池配置(与 database.php 对齐)
|
||||||
'pool' => [
|
'pool' => [
|
||||||
'max_connections' => 5, // 最大连接数
|
'max_connections' => (int) env('DB_POOL_MAX', 20),
|
||||||
'min_connections' => 1, // 最小连接数
|
'min_connections' => (int) env('DB_POOL_MIN', 2),
|
||||||
'wait_timeout' => 3, // 从连接池获取连接等待超时时间
|
'wait_timeout' => (float) env('DB_POOL_WAIT_TIMEOUT', 1.0),
|
||||||
'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收
|
'idle_timeout' => (int) env('DB_POOL_IDLE_TIMEOUT', 60),
|
||||||
'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒
|
'heartbeat_interval' => 50,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ use plugin\saiadmin\app\middleware\SystemLog;
|
|||||||
use plugin\saiadmin\app\middleware\CheckLogin;
|
use plugin\saiadmin\app\middleware\CheckLogin;
|
||||||
use plugin\saiadmin\app\middleware\CheckAuth;
|
use plugin\saiadmin\app\middleware\CheckAuth;
|
||||||
|
|
||||||
|
// 仅对 /core 后台路由生效,避免 /api 请求经过登录/权限/操作日志中间件,提升接口响应
|
||||||
return [
|
return [
|
||||||
'' => [
|
'core' => [
|
||||||
CheckLogin::class,
|
CheckLogin::class,
|
||||||
CheckAuth::class,
|
CheckAuth::class,
|
||||||
SystemLog::class,
|
SystemLog::class,
|
||||||
|
|||||||
Reference in New Issue
Block a user