ThinkPHP 6.1 接口日志需在中间件中捕获原始入参(POST用getRawContent、GET用QUERY_STRING)和出参(getContent后重置),结构化记录IP、URL、参数等,分类归档并配置日志级别与路径权限。

ThinkPHP 6.1 记录接口入参和出参日志,关键在于“原始性”和“时机”——入参必须在框架过滤前捕获,出参需在响应发出前截取,且两者都应结构化、可追溯。靠 input() 或 request()->param() 直接记录会丢失原始内容(如 HTML 标签被转义、空格被 trim),而仅用 Log::info() 打点又容易漏掉异常路径或异步响应。
入参日志:在中间件里抓原始请求体
控制器执行前,原始数据就已存在,但 ThinkPHP 默认不保留。必须在中间件中统一处理:
- 对 POST/PUT/DELETE 请求,调用
$request->getRawContent()获取原始 body;是 JSON 就json_decode($raw, true)解析,别依赖input('xxx')反推 - 对 GET 请求,用
$request->server('QUERY_STRING')拿完整查询串,再parse_str()解析——能保留+、%20、空值等原始编码特征 - 避免在控制器里逐个写
Log::info($this->request->param()),既易遗漏,又记录的是过滤后值 - 推荐字段:IP、URL、method、原始参数(JSON 编码)、时间戳;敏感字段如密码可做掩码(如
'password' => '***')
出参日志:拦截响应对象并序列化
响应内容在 Response 对象中,需在中间件 handle() 返回前读取其内容:
- 在中间件末尾获取响应:
$response = $next($request),然后调用$response->getContent() - 若返回是 JSON,先尝试
json_decode($content, true)再记录,避免日志里全是乱码或 HTML 片段 - 注意:
getContent()只能调用一次(底层是 stream),记录后需用$response->withContent($content)重置,否则前端收不到响应 - 建议只对 API 路由(如
/api/前缀)开启出参记录,避免大文件或图片接口刷爆日志
审计友好:分类记录 + 异常兜底
单纯记日志不够,得让审计人员能快速定位问题:
立即学习“PHP免费学习笔记(深入)”;
- 用
Log::record(..., 'info', 'api')指定分类,后续可通过runtime/log/api/单独归档 - 验证失败时(
ValidateException),立刻记录入参全量(json_encode($request->param(), JSON_UNESCAPED_UNICODE)),不要等进业务逻辑 - 出参若含错误堆栈(如开发环境抛异常),确保
config/log.php中'trace' => true已启用,否则只记一行提示 - 生产环境避免记录全部出参,可配置开关:只记录
status=0(失败)或code != 200的响应
配置与落地细节
日志不是写了就能用,几个硬性条件必须满足:
- 确认
config/app.php中'log' => ['level' => ['info', 'error']]已显式声明级别,仅设type => File不生效 - 日志路径
runtime/log/必须可写,PHP 进程用户(如www-data)需有权限,别用777 - 若用 Swoole 或 RoadRunner,日志默认异步刷盘,查
runtime/log/年月/日.log文件,别盯控制台 - 禁用所有
input($key, $default, $filter)中的$filter参数,改用显式过滤后再记录原始值



















