Laravel 5中的中间件是如何工作的?

6
我正在尝试理解Laravel 5中的中间件是如何工作的。我查看了中间件接口并理解到必须实现一个包含名为“handle”的方法的类。在“handle”方法中,会调用闭包。但我不明白,闭包应该传入什么参数。哪个类会调用我的中间件?它在底层是如何工作的?也许它像“foreach”,所有中间件将依次被调用? 更新: 我正在尝试实现自己的中间件:
interface Middleware
{
    public function handle($request, Closure $next);
}

class MiddlewareCollection
{
    private $middlewares;
    private $request;

    public function __construct(Array $middlewares, $request)
    {
        $this->middlewares = $middlewares;
        $this->request = $request;
    }

    public function run()
    {
        $this->next(current($this->middlewares), $this->request);
    }

    private function next(Middleware $middleware, $request)
    {
        $middleware->handle($request, function($request) {
        //How can I call the next middleware?
        });

    }
}

class FirstMiddleware implements Middleware
{
    public function handle($request, Closure $next) {
        echo $request.'first ';
        return $next($request);
    }
}

class SecondMiddleware implements Middleware
{
    public function handle($request, Closure $next) {
        echo $request.'second ';
        return $next($request);
    }
}

class ThirdMiddleware implements Middleware
{
    public function handle($request, Closure $next) {
        echo $request.'third ';
        return $next($request);
    }
}


$middlewares = [
    'first'     => new FirstMiddleware(),
    'second'    => new SecondMiddleware(),
    'third'     => new ThirdMiddleware()
];

$middlewareCollection = new MiddlewareCollection($middlewares, 'Request');

$middlewareCollection->run();

这样做是否正确呢?另外我也不明白在我的MiddlewareCollection类中,应该如何调用next()方法来调用下一个中间件。


中间件,以前称为过滤器,由MiddlewareServiceProvider处理,它们的逻辑在路由访问时执行,在请求接收和请求注入到路由器之间的“中间”某处。 - Paul Vidal
我认为@TheMrbikus理解了中间件的工作流程,但他想要了解的是闭包$next在哪里编写和调用。他向你展示了处理方法如何调用+闭包的逻辑,我觉得没有人理解他的问题。 - Danny hax
@Dannyhax 是的,兄弟,你说得完全正确! :) 实际上,我已经编写了我的中间件调度程序。如果你感兴趣,可以查看 https://github.com/SmirnovW/light-middleware-dispatcher - TheMrbikus
2个回答

6

这篇博客文章非常有用,可以解释中间件是如何工作的,以及如何从头开始构建中间件。

但是我将使用 Laravel 自带的示例,即身份验证中间件 (app/Http/Middleware/Authenticate.php)。此中间件保护路由并确保试图访问它们的用户已登录。

public function handle($request, Closure $next)
    {
        if ($this->auth->guest()) {
            if ($request->ajax()) {
                return response('Unauthorized.', 401);
            } else {
                return redirect()->guest('auth/login');
            }
        }

        return $next($request);
    }
handle 函数是我们所要做的所有工作,在这种情况下,它首先接受 $request,即我们要前往的地方或发送到服务器的请求。
接下来,我们使用 if ($this->auth->guest()) 检查用户是否已登录或是一个访客。 如果我们已经登录,则会返回 false,并继续执行 return $next($request);,使我们能够像平常一样继续进行。 如果我们没有登录且是一个访客,我们将通过该语句作为 true 并继续使用 if 语句。
然后,我们将会遇到:
if ($request->ajax()) {
                return response('Unauthorized.', 401);
            }

这可能不需要解释,但它检查请求是否为Ajax调用,如果是,则返回401未授权响应。

如果它不是一个Ajax请求,那么我们就会遇到这个问题:

else {
                return redirect()->guest('auth/login');
            }

这将重定向访客到登录页面。一旦他们登录,请求就可以继续进行,他们的请求将像正常情况下一样继续。

因此,我可以使用这个中间件来保护路由www.mywebsite.com/admin,如果我没有登录,则会被重定向到www.mywebsite.com/auth/login,一旦我登录了,我就可以返回到原始请求www.mywebsite.com/admin,并且不会有任何麻烦。

正如我之前提到的那样,先查看博客文章,因为它包含一些有用的解释和更简单的示例。


谢谢您提供这些示例,非常有帮助!我已经更新了我的问题,您能否看一下我的代码并发表您的意见? - TheMrbikus

3

在 Laravel 5 之前,中间件被称为过滤器。中间件拦截请求并在您的中间件类内处理下一步工作。根据您如何处理它,有两种类型的中间件。

在控制器传递控制权之前,将检查 before 中间件。逻辑在您的处理方法中。例如,您想要一个已登录用户才能在留言板上发布留言。因此,如果应用了 before 中间件,并且您的逻辑如下:

  • 检查用户是否未登录
  • 重定向他们回到登录页面
  • 否则,让请求继续进行
代码将如下所示:

public function handle($request, Closure $next)
{
    // Perform action

    return $next($request);
}


在控制器完成所有工作并且响应将要传递给用户之后,后置中间件会进行检查。为此,您可以将其视为已进行 API 请求,并希望在每个请求完成后刷新令牌。对于此操作,代码如下:


``` app.use((req, res, next) => { // some code here next(); }); ```
public function handle($request, Closure $next)
{
    $response = $next($request);

    // Perform action

    return $response;
}

为了简单起见,您可以将$next方法视为它将控制权传递给控制器。对于前置中间件,它会检查逻辑,然后将控制权返回给控制器,并最终返回响应。
另一方面,后置中间件将控制权传递给控制器,当控制器完成其工作时,$response变量上存储了一些内容并执行了一些逻辑。之后,它将返回$response。

希望现在清楚了。


非常感谢您提供这些信息!我已经更新了我的问题,您能否看一下我的代码并发表您的意见? - TheMrbikus
我不明白您想要做什么或达到什么目的。 - ssi-anik
我尝试实现自己的中间件机制,以了解它在底层是如何工作的 =) - TheMrbikus
你做错了,中间件不是你应该实例化和运行的东西。有一个工匠命令来创建中间件。你可以这样做,这将帮助你创建新的中间件。无论你想检查什么(逻辑),都将在handle方法中。还有一件事,中间件是注入到路由和控制器构造函数中的。你必须将该中间件添加到app/Http/Kernel.php中的$routedmiddlware数组中,并使用关键字在后续所需的地方使用。看一下-> https://gist.github.com/ssi-anik/1955cae190394b865657 - ssi-anik
顺便说一句,如果您认为这让您理解了中间件的基本概念,如果您愿意,可以将其标记为已接受的答案。 :) - ssi-anik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接