全局中间件之 TrimStrings
简介
上一章,我们知道了 第二个 全局中间件 ValidatePostSize 作用:根据 php.ini 中的 post_max_size 值对请求体的大小进行判断,截取过大异常,并抛出 413 异常。
这一章,我们来看 第三个 全局中间件 TrimStrings。
通过字面意思我们可以看出,是对请求内容进行 前后空白字符清理。

核心作用:清理 $_GET 和 $_POST 两个数组值的前后空白字符。
中间件 App\Http\Middleware\TrimStrings
首先说一点,此中间件的 handle 方法,没有在当前中间件类中,而是在它的 爷爷 类中。
App\Http\Middleware\TrimStrings
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
class TrimStrings extends Middleware
{
/**
* 排除指定字段名(key)的值,即以下面为 key 的 value 将不进行空白字符清理
*/
protected $except = [
'password',
'password_confirmation',
];
}
爸爸类 Illuminate\Foundation\Http\Middleware\TrimStrings
<?php
namespace Illuminate\Foundation\Http\Middleware;
class TrimStrings extends TransformsRequest
{
protected $except = [
//
];
/**
* 核心方法:空白字符串清理,此方法将在 handle 中最终调用
*/
protected function transform($key, $value)
{
// 首先排除掉不进行空白字符串的键值对
if (in_array($key, $this->except, true)) {
return $value;
}
// trim 内置函数,进行值空白字符清理工作
return is_string($value) ? trim($value) : $value;
}
}
爷爷类 Illuminate\Foundation\Http\Middleware\TransformsRequest 中的 handle 方法
public function handle($request, Closure $next, ...$attributes)
{
// 传递给此中间件的附加属性,索引数组。
$this->attributes = $attributes;
// 清理 $_GET 和 $_POST 的前后空白字符
$this->clean($request);
// 进入下一个中间件
return $next($request);
}
关于 $attributes 如何传递过来的,看下图


在类名的后面拼接 ':参数1,参数2,参数3,...,参数n' 这种格式的字符串,即可传入到中间件 handle 方法中,以索引数组的形式哦。
但是,我要命,没找到传过来的附加属性有什么用,,难道让我们在 App\Http\Middleware\TrimStrings 中间件中自己写方法? 可能是吧。
我们继续看 $this->clean($request)
protected function clean($request)
{
// 清理 $_GET 中值的空白符
$this->cleanParameterBag($request->query);
// $_POST 传递方式是不是通过 JSON 进行传递的
if ($request->isJson()) {
// 是通过JSON传递的,那么转成数组,再清理
$this->cleanParameterBag($request->json());
} else {
// 不是通过JSON传递的,直接清理 $_POST 空白符
$this->cleanParameterBag($request->request);
}
}
$request->isJson() 怎么知道是不是通过 JSON 传递数据的?其根本原理,是搜索 请求头 CONTENT_TYPE 内容有没有 ['/json', '+json'] 这两种字符串,有则是 JSON 传递,没有则不是。
通过上面,我们看到核心清理在 cleanParameterBag 方法中。
protected function cleanParameterBag(ParameterBag $bag)
{
$bag->replace($this->cleanArray($bag->all()));
}
看着是不是头大,一堆方法调用。
先看 ParameterBag $bag 是什么鬼:$bag,相信前面看过 Laravel 请求对象之 SymfonyRequest 童鞋,应该了解。这里面就封装了 $_GET, $_POST, $_COOKIE, $_SERVER 的数据,当然这 4 个不是封装在一起,而是分开封装的,每一个封装一个 ParameterBag $bag。
我们再回看 $this->cleanParameterBag($request->query); 这句,看到参数 $request->query 吗,它返回的就是封装成 ParameterBag $bag 的 $_GET。而 $request->request 是封装成 ParameterBag $bag 的 $_POST。
其中 $bag->all() 返回的就是 $_GET 或者 $_POST 的原生数组,当然是没清理空白字符的旧数据啦
而 $bag->replace($newGETorPOST) 是指以 $newGETorPOST 为新数据,替换旧的 $_GET 或 $_POST
好了,既然要替换,我们首先要有新的 GETorPOST ,它是怎么来的呢
就是通过 $this->cleanArray($bag->all())
protected function cleanArray(array $data)
{
return collect($data)->map(function ($value, $key) {
return $this->cleanValue($key, $value);
})->all();
}
看到这,是不是又蒙啦。其实很简单了,collect($data) 返回的是 Eloquent 集合。
好了,既然知道 map 方法就是迭代数组元素,传入 $this->cleanValue($key, $value); 进行处理,那么我们就看一下这个方法
protected function cleanValue($key, $value)
{
if (is_array($value)) {
return $this->cleanArray($value);
}
return $this->transform($key, $value);
}
看到没,之前我说过,$this->transform($key, $value); 这个核心方法,在这里进行了调用。
上面的 if 判断是进行多层数组的处理。
好了,到这里,这个中间件的作用,就讲完了。
本篇如有错误、不当或者需补充的内容,请各位同僚多提宝贵意见。
Laravel 之道
关于 LearnKu
推荐文章: