zoukankan      html  css  js  c++  java
  • laravel框架的中间件middleware的详解

    本篇文章给大家带来的内容是关于laravel框架的中间件middleware的详解,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

    laravel中间件是个非常方便的东西,能将一些逻辑实现解耦,并且在laravel中,
    中间件的编写也是非常的方便。谁用谁知道。

    1.装饰器模式

    laravel中的中间件使用的就是装饰器模式,什么是[装饰器模式][1],先去了解一下吧,这里大概说一下,就是这个模式主要的就是用于解决 当一个类需要动态扩展功能的时候,使用继承的方式会让子类膨胀,并且这个扩展的功能是个公用功能的情况下,不利于功能的复用以及代码的解耦。

    在laravel,使用对于使用这种模式的功能,称为请求处理管道,也就是pipeline

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    //公共接口

    interface middleware {

            public static function handle(Closure $next);

        }

    //装饰器1

    class MiddleStepOne implements middleware{

            public static function handle(Closure $next) {

                echo "前期处理的第一步"."<br>";

                $next();

                echo "后期处理的第一步"."<br>";

            }

        }

    //装饰器2

    class MiddleStepTwo implements middleware{

        public static function handle(Closure $next) {

            echo "前期处理的第二步"."<br>";

            $next();

            echo "后期处理的第二步"."<br>";

        }

    }

     

    function goFunc() {

        return function ($step,$className) {

          return function () use ($step,$className) {

              return $className::handle($step);

          };

        };

    }

     

    $pip = array(

        MiddleStepOne::class,

        MiddleStepTwo::class,

    );

    $pip = array_reverse($pip);  //反转数组,以求达到要求的顺序运行

    $first = function (){

        echo "前期处理完毕"."<br>";

    };  //实际要处理的函数

    $a = array_reduce($pip,goFunc(),$first); //遍历pip数组,并将first作为第一个参数传递进去

    $a(); //执行

    输出:

    这个就是一个简单的基于装饰器模式的管道。他的本质其实就是基于闭包和递归。

    通过分析这个程序,对于最终生成的$a变量,它的值大概是这样的 MiddleStepOne.handle(MiddleStepTwo.handle(first)),当执行的时候因为在handle中有个next()函数的存在,所以这是一个递归的调用。对于laravel的中间件,他的实现原理也是和这个一样的。

    链接:https://pan.baidu.com/s/1v5gm7n0L7TGyejCmQrMh2g 提取码:x2p5

    免费分享,但是X度限制严重,如若链接失效点击链接或搜索加群 群号518475424

    2.laravel中的中间件和请求处理管道

    在laravel中,我们我们可以通过设置中间件来在请求执行之前做一些预先的处理。

    从请求入口 public/index.php开始

    重要的是这段代码:即 处理请求,返回请求的响应

    1

    2

    3

    $response = $kernel->handle(

    $request = IlluminateHttpRequest::capture() //创建一个请求实例

    );

    接着我们进入kernel中看他的具体实现 IlluminateFoundationHttpKernel.php中


    关于dispatchToRouter()函数请大家自己去看,这里就不多说了。

    接下来就是激动人心的PipeLine类了,

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    72

    73

    74

    75

    76

    77

    78

    79

    80

    81

    82

    83

    84

    85

    86

    87

    88

    89

    90

    91

    92

    93

    94

    95

    96

    97

    98

    99

    100

    101

    102

    103

    104

    105

    106

    107

    108

    109

    110

    111

    112

    113

    114

    115

    116

    117

    118

    119

    120

    121

    122

    123

    124

    125

    126

    127

    128

    129

    130

    131

    132

    133

    134

    135

    136

    137

    138

    139

    140

    141

    142

    143

    144

    145

    146

    147

    148

    149

    150

    151

    152

    153

    154

    155

    156

    157

    158

    159

    160

    161

    162

    163

    164

    165

    166

    167

    168

    169

    170

    171

    172

    173

    174

    175

    176

    177

    178

    179

    180

    181

    182

    183

    184

    185

    186

    187

    188

    <?php

     

    namespace IlluminatePipeline;

     

    use Closure;

    use RuntimeException;

    use IlluminateContractsContainerContainer;

    use IlluminateContractsPipelinePipeline as PipelineContract;

     

    class Pipeline implements PipelineContract

    {

        /**

         * The container implementation.

         *

         * @var IlluminateContractsContainerContainer

         */

        protected $container;

     

        /**

         * The object being passed through the pipeline.

         *

         * @var mixed

         */

        protected $passable;

     

        /**

         * The array of class pipes.

         *

         * @var array

         */

        protected $pipes = [];

     

        /**

         * The method to call on each pipe.

         *

         * @var string

         */

        protected $method = 'handle';

     

        /**

         * Create a new class instance.

         *

         * @param  IlluminateContractsContainerContainer|null  $container

         * @return void

         */

        public function __construct(Container $container = null)

        {

            $this->container = $container;

        }

     

        /**

         * Set the object being sent through the pipeline.

         *

         * @param  mixed  $passable

         * @return $this

         */

        public function send($passable)

        {

            $this->passable = $passable;

     

            return $this;

        }

     

        /**

         * Set the array of pipes.

         *

         * @param  array|mixed  $pipes

         * @return $this

         */

        public function through($pipes)

        {

            $this->pipes = is_array($pipes) ? $pipes : func_get_args();

     

            return $this;

        }

     

        /**

         * Set the method to call on the pipes.

         *

         * @param  string  $method

         * @return $this

         */

        public function via($method)

        {

            $this->method = $method;

     

            return $this;

        }

     

        /**

         * Run the pipeline with a final destination callback.

         *

         * @param  Closure  $destination

         * @return mixed

         */

        public function then(Closure $destination)

        {

            $pipeline = array_reduce(

                array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)

            );

     

            return $pipeline($this->passable);

        }

     

        /**

         * Get the final piece of the Closure onion.

         *

         * @param  Closure  $destination

         * @return Closure

         */

        protected function prepareDestination(Closure $destination)

        {

            return function ($passable) use ($destination) {

                return $destination($passable);

            };

        }

     

        /**

         * Get a Closure that represents a slice of the application onion.

         *

         * @return Closure

         */

        protected function carry()

        {

            return function ($stack, $pipe) {

                return function ($passable) use ($stack, $pipe) {

                    if (is_callable($pipe)) {

                        // If the pipe is an instance of a Closure, we will just call it directly but

                        // otherwise we'll resolve the pipes out of the container and call it with

                        // the appropriate method and arguments, returning the results back out.

                        //如果pip也就中间件函数是一个闭包可调用函数,就直接返回这个闭包函数就行了

                        //这里我还没有找到对应的使用场景,后续补充

                        return $pipe($passable, $stack);

                    } elseif (! is_object($pipe)) {

                        list($name, $parameters) = $this->parsePipeString($pipe);

     

                        // If the pipe is a string we will parse the string and resolve the class out

                        // of the dependency injection container. We can then build a callable and

                        // execute the pipe function giving in the parameters that are required.

                        $pipe = $this->getContainer()->make($name);

     

                        $parameters = array_merge([$passable, $stack], $parameters);

                    } else {

                        // If the pipe is already an object we'll just make a callable and pass it to

                        // the pipe as-is. There is no need to do any extra parsing and formatting

                        // since the object we're given was already a fully instantiated object.

                        $parameters = [$passable, $stack];

                    }

     

                    return method_exists($pipe, $this->method)

                                    ? $pipe->{$this->method}(...$parameters)

                                    : $pipe(...$parameters);

                };

            };

        }

     

        /**

         * Parse full pipe string to get name and parameters.

         *

         * @param  string $pipe

         * @return array

         */

        protected function parsePipeString($pipe)

        {

            list($name, $parameters) = array_pad(explode(':', $pipe, 2), 2, []);

     

            if (is_string($parameters)) {

                $parameters = explode(',', $parameters);

            }

     

            return [$name, $parameters];

        }

     

        /**

         * Get the container instance.

         *

         * @return IlluminateContractsContainerContainer

         * @throws RuntimeException

         */

        protected function getContainer()

        {

            if (! $this->container) {

                throw new RuntimeException('A container instance has not been passed to the Pipeline.');

            }

     

            return $this->container;

        }

    }

    总的来说pipeLine类的实现和我之前写的修饰器是差不多,这里主要麻烦的地方就在于就在于

    protected function carry()函数内部,对于当pip是闭包,字符串,还有对象的处理。

    之前觉得laravel的中间件是个很神秘的东西,但是看了之后才觉得也就那样,很精巧,在实际开发中这种模式也是很有帮助的,例如我们目前用的一个gateway项目,因为没有使用任何框架,所以将判断条件剥离,写入到中间件中, 这样实现了一定程度上的模块化编程。

  • 相关阅读:
    Spring多数据源动态切换
    IntelliJ Idea使用代码格式化,Tab制表符进行缩进
    idea 快捷键
    final关键字的功能概述
    IntelliJ Idea 常用快捷键列表
    Log4j.properties配置详解
    IDEA添加try catch快捷键
    使用 JMeter 进行压力测试
    idea 复制当前行到下一行快捷键
    js父窗口opener与parent
  • 原文地址:https://www.cnblogs.com/it-3327/p/11794804.html
Copyright © 2011-2022 走看看