作为程序员一定要保持良好的睡眠,才能好编程

第九课 laravel 中间件的使用及理解

发布时间:2020-09-18


官方文档:

https://learnku.com/docs/laravel/7.x/middleware/7459



laravel 中间件


中间件默认存放在 app\http\middleware 目录下


中间件是做什么?


是处理请求判断的,


如果是  则真  继续执行   如果false  则停止。


使用场景:


如果这些所有if  else  写在业务代码中,呵呵 则越来越多  越来越乱 最后难以维护。


中间件可以为我们解决这个难题。


中间件分两种:


全局中间件


路由中间件




先看一下中间件怎么写:


First.php 先写第一个中间件: age不能==200 其他请求过,只有200 会拦截。



namespace App\Http\Middleware;
use Closure;
class First {
  public function handle($request, Closure $next) {
    if ($request->input('age') == 200) {
      echo 'age 不能等于200';
      exit;
    }
    return $next($request);
  }
}


第一个中间件就写完了。你可以举一反三,比如验证是否ajax() 请求,如果是则 返回header头信息。


第二步:中间件如何使用?



1、全局中间件使用


lumen 在 bootstarp/app.php 中 


$app->middleware([

  App\Http\Middleware\First::class,

  App\Http\Middleware\Second::class,

]);


注册到了全局中,任何请求都会执行到两个中间件。



执行的顺序,使用注册顺序


$router->get('user/tt','UserController@tt'); 

查看日志

[2018-07-23 14:47:07] lumen.INFO: first middleware  1532328427.5392  

[2018-07-23 14:47:07] lumen.INFO: Second middleware 中间件e  1532328427.5402  



//如果这里也定义了 中间件会走两遍

$router->get('user/tt', ['middleware' =>'routemiddle', 'uses' => 'UserController@tt']);

查看日志

[2018-07-23 14:47:07] lumen.INFO: first middleware  1532328427.5392  

[2018-07-23 14:47:07] lumen.INFO: Second middleware 中间件e  1532328427.5402  

[2018-07-23 14:47:07] lumen.INFO: RouteMiddle  1532328427.5412  


这是中间件执行的过程,按照顺序执行的。




2、路由中间件使用(其他地不使用)


再来看看这种写法,这叫路由写法

看到中间件使用的是routemiddle 这是一个字符串,那么为什么会能使用呢?

$router->get('user/tt',['middleware'=>'routemiddle','uses'=>'UserController@tt']);


当然也可以这样写:

$router->get('user/tt',['middleware'=>App\Http\Middleware\RouteMiddle::class,'uses'=>'UserController@tt']);


看这里:bootstrap/app.php


有这么一行代码: 注册了路由名 ,但程序并不默认执行。


$app->routeMiddleware([

  'routemiddle' => App\Http\Middleware\RouteMiddle::class,

]);

 




 public function handle($request, Closure $next)
 
  要让请求继续传递到应用程序中(即允许「通过」中间件验证的),只需使用 $request 作为参数去调用回调函数 $next
 
 
  前置 & 后置中间件
  中间件是在请求之前或之后运行取决于中间件本身。例如, 接下来的这个中间件将在应用处理请求 之前 执行其任务
 
  class BeforeMiddleware
{
    public function handle($request, Closure $next)
    {
        // Perform action

        return $next($request);
    }
}


而接下来的这个中间件将在应用处理请求 之后 执行其任务:(处理请求之后触发  )
class AfterMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        // 执行操作   先执行的response 然后再返回的,这就是后置执行 

        return $response;
    }
}


中间件中只有一个方法,就是handle() 。可以在这里执行相对应的执行和判断。




我们处理的请求一般是:加减密 、cros跨域 、 请求拦截、错误信息拦截、



传递参数给中间件



附加的中间参数会在 $next 参数之后传递给中间件:

定义路由时通过一个 : 来隔开中间件名称和参数来指定中间件参数。多个参数就使用逗号分隔:

如果多个参数使用逗号分隔


'login_check_info:2,login'


Route::middleware(['login_check_info:2'])->group(function () {


});



class LoginCheckInfo
{
    public $expire = 300; //5分钟过期
    /**
     *
     * handle
     * @param Request $request
     * @param Closure $next
     * @param $accountType //账号类型 1:药师,2:管理员
     * @return mixed
     * @throws ApiException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     *
     * @date 2020/3/16 11:31
     */
    public function handle(Request $request, Closure $next, $accountType)
    {
        $openId = $request->header('BHC-GATEWAY-OPEN-ID', '');
       
          if ($pharmacist['accountType'] != $accountType) {
              //取反操作
              if ($accountType == 2) {
                  throw new ApiException('此账号为药师账号,请更换为管理员账号', StatusCode::CHANGE_ACCOUNT_MANAGER);
              }
              if ($accountType == 1) {
                  throw new ApiException('此账号为管理员账号,请更换为药师账号', StatusCode::CHANGE_ACCOUNT_PHARMACIST);
              }
          }
        return $next($request);
    }
}




中间件支持匿名函数写法


Route::middleware(['login_check_info'])->middleware(
function( $request,  $next){
    \Illuminate\Support\Facades\Log::info('test');
    return $next($request);
})->group(function () {

  
});



中间件传递参数到控制器


方式1


中间件

class MidParams //中间件
{
    public function handle($request, Closure $next)
    {
        $mid_params = ['mid_params'=>'this is mid_params'];
        $request->attributes->add($mid_params);//添加参数

        return $next($request);//进行下一步(即传递给控制器)
    }
}


控制器


 //注意:$request->attributes->add这种方法 input()取不到值        只能用get('xxx')取到值


class MidController extends  Controller { //控制器
    public function testMidFunc(Request $request) {
        $input_params =  $request->input();//获取参数
        $mid_params = $request->get('mid_params');//中间件产生的参数
        return ['my_params'=>$input_params,
        'mid_params'=>$mid_params];
        
        //注意:$request->attributes->add这种方法 input()取不到值        只能用get('xxx')取到值
    }
}


方式2


中间件

class MidParams //中间件
{
    public function handle($request, Closure $next)
    {
        $mid_params = ['mid_params'=>'this is mid_params'];
        $request->merge($mid_params);//合并参数
        return $next($request);
    }
}


控制器

class MidController extends  Controller { //控制器
    public function testMidFunc(Request $request) {
        $all_params =  $request->input();//获取参数
        return ['all_params'=>$all_params];
    }
}