全局中间件之 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 判断是进行多层数组的处理。
好了,到这里,这个中间件的作用,就讲完了。