Middleware (MiddleWare)



How to quickly generate middleware?

Through the command line: Under the app/middleware directory Generate a Check middleware

php think make:middleware Check

Middleware code:

<?php

namespace app\middleware;

class Check
{
    public function handle($request, \Closure $next)
    {
        if ($request->param('name') == 'think') {
            return redirect('index/think');
        }

        return $next($request);
    }
}

The entry execution method of the middleware must be the handle method, and the first parameter is the Request object, and the second parameter is a closure Bag.

The return value of the middleware handle method must be a Response object.

In this middleware, we perform redirection processing when we judge that the name parameter of the current request is equal to think. Otherwise, the request will be passed further to the application. To continue passing the request to the application, just call the callback function $next with $request as parameter.

Under certain requirements, you can use the third parameter to pass in additional parameters.

<?php

namespace app\middleware;

class Check
{
    public function handle($request, \Closure $next, $name)
    {
        if ($name == 'think') {
            return redirect('index/think');
        }

        return $next($request);
    }
}

End scheduling

Middleware supports defining a callback mechanism before the request ends. You only need to add the end method in the middleware class.

    public function end(\think\Response $response)
    {
        // 回调行为
    }

Note that there cannot be any response output in the end method. Because the request response output has been completed when the callback is issued.

Pre/post middleware

Whether the middleware is executed before or after the specific operation is requested depends entirely on the definition of the middleware itself.

The following is a middleware for pre-behavior

<?php

namespace app\middleware;

class Before
{
    public function handle($request, \Closure $next)
    {
        // 添加中间件执行代码

        return $next($request);
    }
}

The following is a middleware for post-behavior

<?php

namespace app\middleware;

class After
{
    public function handle($request, \Closure $next)
    {
		$response = $next($request);

        // 添加中间件执行代码

        return $response;
    }
}

Middleware methods can also support dependency injection.

Let’s take a more practical example. We need to determine whether the current browser environment is WeChat or Alipay

namespace app\middleware;

/**
 * 访问环境检查,是否是微信或支付宝等
 */
class InAppCheck
{
    public function handle($request, \Closure $next)
    {
        if (preg_match('~micromessenger~i', $request->header('user-agent'))) {
            $request->InApp = 'WeChat';
        } else if (preg_match('~alipay~i', $request->header('user-agent'))) {
            $request->InApp = 'Alipay';
        }
        return $next($request);
    }
}

Then add a middleware.php file to your mobile version of the application
For example:/path/app/mobile/middleware.php

return [
    app\middleware\InAppCheck::class,
];

Then in your controller you can get the relevant value through $this->request->InApp

Define the middleware alias

You can directly predefine the middleware in middleware.php in the application configuration directory (in fact, it is to add an alias identifier), for example:

return [
    'alias' => [
        'auth'  => app\middleware\Auth::class,
        'check' => app\middleware\Check::class,
    ],
];

can support the use of aliases Define a set of middleware, for example:

return [
    'alias' => [
        'check' => [
            app\middleware\Auth::class,
            app\middleware\Check::class,
        ],
    ],
];

Registration middleware

The new version of middleware is divided into global middleware and application middleware ( There are four groups (valid in multi-application mode), routing middleware and controller middleware.

The execution order is: global gradually->application middleware->routing middleware->controller middleware

global middleware

Global middleware is defined in the middleware.php file under the app directory, using the following method:

<?php

return [
	\app\middleware\Auth::class,
    'check',
    'Hello',
];

The registration of middleware should use the complete class name, if the middleware alias has been defined (or grouping) can be used directly.

The execution order of global middleware is the definition order. Middleware parameters can be passed in when defining global middleware, and two methods are supported.

<?php

return [
	[\app\http\middleware\Auth::class, 'admin'],
    'Check',
    ['hello','thinkphp'],
];

The above definition means that the admin parameter is passed to the Auth middleware and the thinkphp parameter is passed to the Hello middleware.

Application middleware

If you use multi-application mode, application middleware definition is supported. You can add the middleware.php file directly under the application directory. The definition method is the same as the global middleware definition, but it will only take effect under the application.

Routing middleware

The most commonly used middleware registration method is to register routing middleware

Route::rule('hello/:name','hello')
	->middleware(\app\middleware\Auth::class);

Supports the registration of multiple middleware

Route::rule('hello/:name','hello')
	->middleware([\app\middleware\Auth::class, \app\middleware\Check::class]);

You can directly predefine the middleware in middleware.php in the application configuration directory (actually, add an alias identifier), for example:

return [
	'auth'	=>	app\middleware\Auth::class,
    'check'	=>	app\middleware\Check::class
];

Then use the middleware alias to register directly in the routing

Route::rule('hello/:name','hello')
	->middleware(['auth', 'check']);

You can support using aliases to define a group of middleware, for example:

return [
	'check'	=>	[
    	app\middleware\Auth::class,
   		app\middleware\Check::class
    ],
];

Then, directly use the following method to register the middleware

Route::rule('hello/:name','hello')
	->middleware('check');

Supports registering middleware for routing groups

Route::group('hello', function(){
	Route::rule('hello/:name','hello');
})->middleware('auth');

Support middleware registration for a certain domain name

Route::domain('admin', function(){
	// 注册域名下的路由规则
})->middleware('auth');

If you need to pass additional parameters to the middleware, you can use it

Route::rule('hello/:name','hello')
	->middleware('auth', 'admin');

If you need to define multiple middlewares, use Array method

Route::rule('hello/:name','hello')
	->middleware([Auth::class, 'Check']);

You can pass in the same extra parameter

Route::rule('hello/:name','hello')
	->middleware(['auth', 'check'], 'admin');

or call it multiple times separately, specifying different parameters

Route::rule('hello/:name','hello')
	->middleware('auth', 'admin')
        ->middleware('hello', 'thinkphp');

If you want a routing middleware to be Global execution (regardless of whether the route matches or not) does not need to be defined in the route. It can be defined directly in the routing configuration file. For example, add:

'middleware'    =>    [
    app\middleware\Auth::class,
    app\middleware\Check::class,
],

to the config/route.php configuration file. In this way, all applications All requests below will execute the Auth and Check middleware.

Use closures to define middleware

You don’t have to use middleware classes. In some simple situations, you can use closures to define middleware, but closures Package functions must return Response object instances.

Route::group('hello', function(){
	Route::rule('hello/:name','hello');
})->middleware(function($request,\Closure $next){
    if ($request->param('name') == 'think') {
        return redirect('index/think');
    }
    
	return $next($request);
});

Controller middleware

Supports defining middleware for controllers. You only need to define the middleware attribute in the controller, for example:

<?php
namespace app\controller;

class Index
{
    protected $middleware = ['auth'];

    public function index()
    {
        return 'index';
    }

    public function hello()
    {
        return 'hello';
    }
}

The auth middleware will be called when the index controller is executed, and the use of complete namespace definitions is also supported.

If you need to set the effective operation in the middle of the controller, you can define it as follows:

<?php
namespace app\controller;


class Index
{
    protected $middleware = [ 
    	'auth' 	=> ['except' 	=> ['hello'] ],
        'check' => ['only' 		=> ['hello'] ],
    ];

    public function index()
    {
        return 'index';
    }

    public function hello()
    {
        return 'hello';
    }
}

The middleware passes parameters to the controller

You can pass the request Pass parameters to the controller (or other places) by object assignment, such as

<?php

namespace app\middleware;

class Hello
{
    public function handle($request, \Closure $next)
    {
        $request->hello = 'ThinkPHP';
        
        return $next($request);
    }
}

and then use

public function index(Request $request)
{
	return $request->hello; // ThinkPHP
}

execution priority# directly in the controller method.

##If you have strict requirements on the execution order of middleware, you can define the execution priority of middleware. Add

return [
    'alias'    => [
        'check' => [
            app\middleware\Auth::class,
            app\middleware\Check::class,
        ],
    ],
    'priority' => [
        think\middleware\SessionInit::class,
        app\middleware\Auth::class,
        app\middleware\Check::class,
    ],
];

in the configuration file