全局请求过滤中间件需在TP6.1.5中调用$request->merge()刷新内部参数缓存,确保param()/input()等返回已清洗值;JSON请求须手动解析并合并;严禁修改超全局变量或仅设filter规则。

ThinkPHP6.1.5中实现全局请求过滤中间件,核心在于在请求进入控制器前完成参数清洗,并确保后续所有 input()、param()、post() 等调用都返回已过滤值。直接修改超全局变量或只处理副本是无效的,必须操作框架内部参数缓存。
必须用 $request->merge() 刷新参数缓存
TP6.1+ 的 Request 对象将解析后的参数缓存在内部属性中。$request->param() 返回的是只读副本,改它没用。唯一生效的方式是调用 merge() 覆盖原始缓存:
- 在中间件
handle()开头获取当前参数:$params = $request->param(); - 对每个字段做清理(如去空格、转义 HTML、截断长度):
$params['title'] = trim(htmlspecialchars($params['title'] ?? '')); - 移除非业务字段(如
_token、callback):unset($params['_token']); - 关键一步:执行
$request->merge($params);—— 这会重置内部$this->param属性 - 之后控制器中任何
$this->request->param('title')都拿到已处理值
JSON 请求体也要单独处理
当接口接收 Content-Type: application/json 时,$request->param() 默认不会自动解析并过滤 JSON 数据:
- 先手动读取原始内容:
$raw = $request->getContent(); - 解码为数组:
$jsonParams = json_decode($raw, true) ?: []; - 清洗每个字段(注意保留嵌套结构):
array_walk_recursive($jsonParams, function(&$v) { $v = is_string($v) ? trim(htmlspecialchars($v)) : $v; }); - 合并进主参数:
$request->merge(array_merge($params, $jsonParams));
避免常见无效写法
以下做法在 TP6.1.5 中无法影响后续 param() 调用,应杜绝:
立即学习“PHP免费学习笔记(深入)”;
- 直接改
$_GET或$_POST—— TP6 已脱离超全局依赖 - 只调用
$request->filter()设置规则但不 merge —— 规则仅在首次调用时触发,且不覆盖缓存 - 在控制器里用
htmlspecialchars()单独处理某个字段 —— 其他地方(如验证器、日志)仍读原始值 - 用
request->only(['a','b'])+ 手动 filter ——only()不触发过滤逻辑,返回仍是原始字符串
注册到全局 HTTP 中间件链
确保中间件在路由解析后、控制器执行前运行:
- 把中间件类加到
app/middleware.php的'http'数组中(不是'route') - 顺序很重要:若同时有日志、鉴权、过滤中间件,过滤应尽量靠前,保证后续中间件也读干净数据
- 不要注册到
'route'数组 —— 此时路由尚未匹配,$request->controller()等方法不可用,且部分参数可能未解析



















