应使用getRawContent()、php://input、中间件拦截、QUERY_STRING提取及日志脱敏五种方法捕获ThinkPHP API原始请求体,覆盖POST/PUT/GET等场景并确保安全合规。

如果您在调试 ThinkPHP 应用时需要完整捕获 API 请求体原始内容(如 JSON、XML 或 raw POST 数据),但发现 request()->param() 或 input() 返回的是已过滤或已解析后的值,则无法还原客户端真实发送的字节流。以下是记录原始请求体的多种可行方法:
一、使用 getRawContent() 捕获原始请求体
该方法适用于 POST、PUT、DELETE 等含请求体的 HTTP 方法,直接读取 PHP 输入流 php://input 的原始字节,未经过任何框架解析或过滤。
1、在控制器方法最顶部调用 $this->request->getRawContent();
2、判断返回值是否为空字符串,若为空则说明非 body 类型请求(如 GET)或已被其他逻辑提前读取;
立即学习“PHP免费学习笔记(深入)”;
3、对非空结果进行日志写入,推荐使用 Log::write() 实时记录,并附加请求时间、IP、URI 等上下文;
4、若为 JSON 格式,可额外执行 json_decode($raw, true) 并校验有效性,无效时仍保留原始字符串入库;
二、通过 php://input 手动读取原始流
绕过框架封装,直接访问底层输入流,确保在任何框架逻辑执行前获取原始数据,适用于所有版本 ThinkPHP 且兼容性最高。
1、使用 file_get_contents('php://input') 获取原始请求体;
2、检查返回值是否为 false 或空,避免因流已被读取导致重复读取失败;
3、将结果与 $_SERVER['REQUEST_METHOD'] 和 $_SERVER['CONTENT_TYPE'] 一并结构化记录;
4、对敏感字段(如 password、token)做掩码处理,例如将值替换为 [REDACTED] 后再写入日志;
三、在中间件中统一拦截并记录
将原始请求体捕获逻辑前置到应用生命周期早期,避免控制器中遗漏,同时支持按路由规则条件启用,降低性能损耗。
1、创建自定义中间件类,实现 handle() 方法;
2、在 handle() 开头调用 $request->getRawContent() 并存入 Request 对象属性(如 $request->rawBody);
3、根据配置项(如 app.debug 或白名单路由)决定是否触发日志写入;
4、使用 Log::write("Raw Body: {$raw}", 'debug', 'api_raw') 写入独立日志通道;
四、GET 请求参数的完整原始捕获
GET 请求无请求体,但其查询字符串(QUERY_STRING)可能包含编码差异、空格、+ 号等原始特征,需避免经 $_GET 自动解码失真。
1、从服务器变量中提取 $_SERVER['QUERY_STRING'] 值;
2、使用 parse_str() 解析为数组,保留原始键名与未 decode 值;
3、对比 request()->get() 结果,识别出因 URL 编码转换导致的差异项;
4、将原始 QUERY_STRING 字符串与解析后数组同时记录,便于审计回溯;
五、日志格式标准化与安全控制
原始请求体日志易暴露敏感信息,必须强制执行脱敏与分级存储策略,防止日志文件成为攻击入口。
1、定义固定日志字段:timestamp、client_ip、method、uri、content_type、raw_length、is_truncated;
2、设置长度阈值(如 2048 字节),超长内容截断并在末尾标记 [TRUNCATED];
3、配置日志驱动为 File 类型并指定独立目录(如 runtime/log/api-raw/),禁止 Web 直接访问;
4、在日志写入前遍历请求体键值,对匹配 password|token|auth|key|secret 的字段值统一替换为 [HIDDEN];



















