基于FastRoute的PSR-15路由接口

1.2.0 2024-08-12 19:31 UTC

This package is auto-updated.

Last update: 2024-09-12 19:35:44 UTC


README

Build status Code coverage Latest version Downloads total License

安装

如果您使用Composer来管理项目的依赖关系,只需在composer.json文件中添加对matthiasmullie/router的依赖即可。

composer require matthiasmullie/router

使用方法

路由

此路由提供了一种简单的方法将路由(请求方法 + 路径)映射到请求处理器。

请求处理器是实现了PSR-15的Psr\Http\Server\RequestHandlerInterface接口的类,它接受一个Psr\Http\Message\ServerRequestInterface对象,并返回一个Psr\Http\Message\ResponseInterface对象。

这本质上只是在FastRoute之上提供了一个简单的PSR-15层。

就是这么简单

use MatthiasMullie\Router\RequestMethods;
use MatthiasMullie\Router\Router;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

// create 2 example request handlers
class RouteOne implements RequestHandlerInterface
{
    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        return new Response(
            200,
            ['Content-Type' => 'application/json; charset=utf-8'],
            json_encode(['message' => 'Hello world']),
        );
    }
}
class RouteTwo implements RequestHandlerInterface
{
    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        return new Response(
            200,
            ['Content-Type' => 'text/html; charset=utf-8'],
            '<html><body><p>Hello world</p></body></html>',
        );
    }
}

// create router instance and add both routes
$this->router = new Router();
$this->router->addRoute(
    RequestMethods::GET,
    '/one',
    new RouteOne(),
);
$this->router->addRoute(
    RequestMethods::GET,
    '/two',
    new RouteTwo(),
);

// route a request, receive response from the matching request handler
$response = $router->handle(
    new ServerRequest('GET', '/one'),
);
echo $response->getBody(); // outputs: {"message":"Hello world"}

分组

为了方便,具有相同前缀的路由可以捆绑在一起组成一个组。

例如

// create router instance and add an individual route
$this->router = new Router();
$this->router->addRoute(
    RequestMethods::GET,
    '/one', // maps to /one
    new RouteOne(),
);

// then 2 more routes with a shared prefix 
$group = $this->router->addGroup('/prefix');
$group->addRoute(
    RequestMethods::GET,
    '/two', // maps to /prefix/two
    new RouteTwo(),
);
$group->addRoute(
    RequestMethods::GET,
    '/three', // maps to /prefix/three
    new RouteThree(),
);

中间件

除了PSR-15的请求处理器之外,此路由还支持PSR-15的Psr\Http\Server\MiddlewareInterface,它围绕请求处理器包装,在处理请求之前和之后执行。

这简化了多个请求处理器之间共享的逻辑,例如身份验证、日志记录等。

可以将中间件添加到单个路由、组内的所有路由或所有路由。

例如

class Middleware implements MiddlewareInterface {
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        // execute something before handling the request,
        // or manipulate the request object
        $request = $request->withAttribute('middleware', 'Hello world');

        // invoke the handler (or the next middleware, if any)
        // and retrieve the response
        $response = $handler->handle($request);

        // execute something after handling the request,
        // or manipulate the response object
        return $response->withAddedHeader('Content-Type', 'application/json; charset=utf-8);
    }
} 

// create router instance and add a route with middleware
$this->router = new Router();
$this->router
    ->addRoute(
        RequestMethods::GET,
        '/one',
        new RouteOne(),
    )
    ->addMiddleware(
        new Middleware(),
    );

// or add a group with middleware that applies to all routes within that group
$this->router
    ->addGroup('/prefix')
    ->addMiddleware(
        new Middleware(),
    )
    ->addRoute(
        RequestMethods::GET,
        '/two',
        new RouteTwo(),
    );

// or add middleware that applies to all routes
$this->router->addMiddleware(
    new Middleware(),
);

异常

默认情况下,无论是在请求处理器/中间件中遇到,还是在路由中(例如无效路由),遇到的任何异常都将简单地抛出。然而,可以添加自定义异常处理器,它会捕获任何异常并返回一个响应。

可以通过向路由器提供MatthiasMullie\Router\ExceptionResponseInterface实例来完成此操作,例如提供的MatthiasMullie\Router\ExceptionResponse。这将捕获任何异常并返回具有适当状态码的响应。

此包还附带一个自定义的MatthiasMullie\Router\Exception类,允许在异常中包含HTTP状态码和头信息。

示例

use MatthiasMullie\Router\Exception;
use MatthiasMullie\Router\ExceptionResponse;

class RouteException implements RequestHandlerInterface
{
    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        throw new Exception('Not Implemented', 501);
    }
}

$this->router = new Router(new ExceptionResponse(new Response()));
$this->router->addRoute(
    RequestMethods::GET,
    '/exception',
    new RouteException(),
);

$response = $router->handle(
    new ServerRequest('GET', '/exception'),
);
// $response now includes the 501 Not Implemented status code & reason phrase

许可证

router遵循MIT许可证。