在ThinkPHP6中间件中记录请求日志,需在handle方法中于鉴权后、控制器执行前结构化采集admin_id、模块/控制器/操作、脱敏params、IP、method、url等字段,优先写入带索引的数据库,敏感操作标记is_sensitive,高并发时可异步落库。

在 ThinkPHP6 中间件里记录请求日志,核心是抓住「请求刚进来、控制器还没执行」这个时机,用中间件统一捕获关键上下文,并结构化落库或写文件。不能靠零散的 Log::write(),也不能只记 URL 和 IP。
必须在中间件 handle 方法里做
中间件是唯一能稳定获取完整请求上下文的位置——路由已解析、Auth 已认证、参数已解析,但控制器逻辑尚未触发。其他方式(如控制器内写日志、Behavior、全局 Log::record)都会漏场景、难过滤、不可审计。
- 注册方式:在
app/middleware.php中加入中间件类,例如app\middleware\AdminLog::class - 执行时机:确保它在鉴权中间件之后运行,才能安全读取
session('admin_id')或Auth::id() - 跳过无关请求:对静态资源(
.js、.css、/public/)、健康检查(/api/ping)、登录登出等接口提前 return,避免日志爆炸
要记录哪些字段才真正有用
光记时间戳和 IP 没意义。日志必须可查、可筛、可聚合,所以字段得拆开存,别塞进一个 text 字段。
-
admin_id:从 session 或 token 解析,未登录填
NULL或0,不为空字符串 -
module / controller / action:用
$request->rule()->getModule()、getController()、$request->action()获取,别解析 URL -
params:调用
$request->param()后,用array_filter()剔除['password', 'token', 'old_password']等敏感键,再 JSON 存入数据库(MySQL 5.7+ 推荐用JSON类型) -
ip / method / url:分别用
$request->ip()、$request->method()、$request->url(true) - created_at:必须加索引,否则按天查日志会全表扫描
写入方式选数据库还是文件
生产环境强烈建议写数据库,便于后续查询、告警、审计;开发或低频场景可用文件,但必须加锁防并发丢行。
立即学习“PHP免费学习笔记(深入)”;
-
写数据库:用
Db::name('admin_log')->insert($data),字段一一对应,避免用 ORM 模型增加额外开销 -
写文件:用
file_put_contents(..., FILE_APPEND | LOCK_EX),格式为每行一个标准 JSON,例如:{"admin_id":102,"action":"user/delete","ip":"192.168.1.5","params":{"id":123},"created_at":"2026-10-29 14:02:00"} - 别用
Log::write($array):它会把数组转成无结构字符串,grep 都难定位
敏感操作和性能注意点
不是所有操作都一样重要,也不是所有日志都能无限制写。
- 对删除用户、修改权限、导出数据等操作,额外加
is_sensitive = 1字段,方便审计时快速筛选 - 异步任务(如队列中的 Excel 导出)不在 HTTP 生命周期内,中间件捕获不到,需在任务内部单独记录
- 高并发下,数据库写入可能成瓶颈,可考虑先写 Redis 队列,再由后台脚本批量落库
- 日志表定期归档,比如按月分表或用 Partition,避免单表超千万行拖慢查询



















