返回介绍

Middleware

发布于 2021-11-04 22:44:46 字数 6993 浏览 983 评论 0 收藏 0

Middleware is a nifty way to wrap the handling of HTTP requests in Flarum. This can allow you to modify responses, add your own checks to the request, and much more. The possibilities are endless!

Flarum maintains a middleware "Pipe" through which all requests pass. Each of the three "applications" (admin, forum, and api) have their own subpipe: after being processed through some shared logic, requests are diverted to one of the pipes based on the path.

A request passes through the middleware layers in order. When the request is handled (a middleware returns something instead of passing the request to the next layer, or throws an exception), the response will move back up the middleware layers in reverse order, before finally being returned to the user. Everything from Flarum's error handler to its authentication logic is implemented as middleware, and so can be supplemented, replaced, reordered, or removed by extensions.


use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;


class YourMiddleware implements MiddlewareInterface {
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        // Logic to run before the request is processed and later middleware is called.
        $response = $handler->handle($request);
        // Logic to run after the request is processed.
        return $response
    }
}

To add a new middleware, simply use the middleware extender in your extension's extend.php file:


use Flarum\Extend;
// use Flarum\Http\Middleware\CheckCsrfToken;


return [
    // Add middleware to forum frontend
    (new Extend\Middleware('forum'))->add(YourMiddleware::class),
    // Admin frontend
    (new Extend\Middleware('admin'))->add(YourMiddleware::class),
    // API frontend
    (new Extend\Middleware('api'))->add(YourMiddleware::class),


    (new Extend\Middleware('frontend'))
        // remove a middleware (e.g. remove CSRF token check )
        ->remove(CheckCsrfToken::class)
        // insert before another middleware (e.g. before a CSRF token check)
        ->insertBefore(CheckCsrfToken::class, YourMiddleware::class)
        // insert after another middleware (e.g. after a CSRF token check)
        ->insertAfter(CheckCsrfToken::class, YourMiddleware::class)
        // replace a middleware (e.g. replace the CSRF check with your own implementation)
        ->replace(CheckCsrfToken::class, YourMiddleware::class)
];

Tada! Middleware registered. Remember that order matters.

Now that we've got the basics down, let's run through a few more things:

If you don't need your middleware to execute under every route, you can add an if to filter it:


use Laminas\Diactoros\Uri;


public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
  {
    $currentRoute = $request->getUri()->getPath();
    $routeToRunUnder = new Uri(app()->url('/path/to/run/under'));


    if ($currentRoute === $routeToRunUnder->getPath()) {
        // Your logic here!
    }


    return $handler->handle($request);
}

If your middleware runs after Flarum\Http\Middleware\ResolveRoute (which is recommended if it is route-dependent), you can access the route name via $request->getAttribute('routeName'). For example:


public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
    if ($request->getAttribute('routeName') === 'register') {
        // Your logic here!
    }


    return $handler->handle($request);
}

Of course, you can use any condition, not just the current route. Simple, right?

Let's refer back to the example and say you're checking a user against an external database during registration. One user registers and they are found in this database. Uh-oh! Let's keep them from registering:


use Flarum\Api\JsonApiResponse;
use Tobscure\JsonApi\Document;
use Tobscure\JsonApi\Exception\Handler\ResponseBag;


public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
    if ($userFoundInDatabase) {
        $error = new ResponseBag('422', [
            [
                'status' => '422',
                'code' => 'validation_error',
                'source' => [
                    'pointer' => '/data/attributes/email',
                ],
                'detail' => 'Yikes! Your email can\'t be used.',
            ],
        ]);
        $document = new Document();
        $document->setErrors($error->getErrors());
      
        return new JsonApiResponse($document, $error->getStatus());
    }


    return $handler->handle($request);
}

Phew! Crisis avoided.

To learn more about the request and response objects, see the PSR HTTP message interfaces documentation.

If you'd like to do something with the response after the initial request has been handled, that's no problem! Just run the request handler and then your logic:


public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
    $response = $handler->handle($request);


    // Your logic...
    $response = $response->withHeader('Content-Type', 'application/json');


    return $response;
}

Keep in mind that PSR-7 responses are immutable, so you'll need to reassign the $response variable every time you modify the response.

Once all is said and done and you aren't returning a response yourself, you can simply pass the request to the next middleware:


return $handler->handle($request);

Great! We're all done here. Now you can make the middleware of your dreams!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文