最稳、最轻量、最容易控制的方式是用中间件拦截before和after阶段:before取请求信息(方法、URL、IP、脱敏后的头及参数),after补响应信息(状态码、耗时、大小),时间戳存$request,敏感字段显式脱敏,日志JSON单行写入并加锁。

直接用中间件拦截 before 和 after 阶段,是最稳、最轻量、也最容易控制的方式。其他方案(比如改日志驱动、塞钩子、在控制器里手写)要么漏请求,要么结构乱,要么性能扛不住。
中间件里怎么同时拿到请求和响应信息
ThinkPHP 的中间件天然支持在请求进入时(before)和响应发出前(after)介入。关键不是“记录什么”,而是“在哪一刻能安全取到完整上下文”:
-
before阶段可取:$request->method()、$request->url(true)、$request->ip()、$request->header('authorization')(需脱敏)、$request->param()(注意:表单/JSON 已解析,非原始体) -
after阶段才可取:$response->getCode()、耗时(用microtime(true) - $request->startTime)、响应大小(strlen($response->getContent())) - 别在
handle()里只做一次记录——before只存起点,after才能拼出完整日志行 - 必须把时间戳存到
$request实例上(如$request->startTime = microtime(true)),否则after阶段拿不到
哪些字段必须脱敏,哪些可以跳过
不脱敏=生产事故。但也不是所有字段都要记,记多了反而查不动:
- 必须脱敏:
authorization头(截取前 8 字符 +***),password、id_card、bank_card等敏感键名——从$request->param()中显式unset,别信前端传空 - 建议跳过:
file类型参数(用$request->hasFile()判断并跳过)、/public/或.js/.css请求(加路径白名单)、健康检查接口(如/api/ping) - 可选记录但要限长:请求体和响应体——超 1KB 就截断,或只记
strlen();JSON 参数建议用json_encode($data, JSON_UNESCAPED_UNICODE)保证中文可读
日志写入时容易卡住或丢数据
同步写文件在高并发下会成瓶颈,而且多个进程写同一文件可能丢行:
- 别直接
Log::info(...)写字符串——它默认走 File 驱动,不结构化,grep都难定位 - 推荐构造数组后
json_encode()成单行写入独立日志文件,例如:file_put_contents(runtime_path('log/api/'.date('Y-m-d').'.log'), $line."\n", FILE_APPEND | LOCK_EX) - 如果用数据库,务必包
try/catch,写失败不能阻断主流程;失败时最多error_log()记个提示 - TP6+ 若跑 Swoole,
memory_get_usage()意义变弱,别依赖它;microtime(true)仍可靠
真正难的不是写代码,是定规则:哪些接口必须记、哪些字段必须脱敏、日志保留几天、谁有权限查——这些没对齐,日志写得再全也是摆设。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











