Menu

全局中间件之 TrimStrings

简介

上一章,我们知道了 第二个 全局中间件 ValidatePostSize 作用:根据 php.ini 中的 post_max_size 值对请求体的大小进行判断,截取过大异常,并抛出 413 异常。

这一章,我们来看 第三个 全局中间件 TrimStrings

通过字面意思我们可以看出,是对请求内容进行 前后空白字符清理

file

核心作用:清理 $_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 如何传递过来的,看下图

file

file

在类名的后面拼接 ':参数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 的使用

集合方法 all 的使用

好了,既然知道 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 判断是进行多层数组的处理。

好了,到这里,这个中间件的作用,就讲完了。

本篇如有错误、不当或者需补充的内容,请各位同僚多提宝贵意见。

本文章首发在 LearnKu.com 网站上。
上一篇 下一篇
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 0
发起讨论 只看当前版本


暂无话题~