Middleware: Router

路由是httpServer必不可少的组件,我们使用nikic的FastRoute来实现一个路由中间件:

  1. <?php
  2. use FastRoute\Dispatcher;
  3. use FastRoute\RouteCollector;
  4. use Minimalism\A\Server\Http\Context;
  5. // 这里继承FastRoute的RouteCollector
  6. class Router extends RouteCollector
  7. {
  8. public $dispatcher;
  9. public function __construct()
  10. {
  11. $routeParser = new \FastRoute\RouteParser\Std();
  12. $dataGenerator = new \FastRoute\DataGenerator\GroupCountBased();
  13. parent::__construct($routeParser, $dataGenerator);
  14. }
  15. // 返回路由中间件
  16. public function routes()
  17. {
  18. $this->dispatcher = new \FastRoute\Dispatcher\GroupCountBased($this->getData());
  19. return [$this, "dispatch"];
  20. }
  21. // 路由中间件的主要逻辑
  22. public function dispatch(Context $ctx, $next)
  23. {
  24. if ($this->dispatcher === null) {
  25. $this->routes();
  26. }
  27. $uri = $ctx->url;
  28. if (false !== $pos = strpos($uri, '?')) {
  29. $uri = substr($uri, 0, $pos);
  30. }
  31. $uri = rawurldecode($uri);
  32. // 从Context提取method与url进行分发
  33. $routeInfo = $this->dispatcher->dispatch(strtoupper($ctx->method), $uri);
  34. switch ($routeInfo[0]) {
  35. case Dispatcher::NOT_FOUND:
  36. // 状态码写入Context
  37. $ctx->status = 404;
  38. yield $next;
  39. break;
  40. case Dispatcher::METHOD_NOT_ALLOWED:
  41. $ctx->status = 405;
  42. break;
  43. case Dispatcher::FOUND:
  44. $handler = $routeInfo[1];
  45. $vars = $routeInfo[2];
  46. // 从路由表提取处理器
  47. yield $handler($ctx, $next, $vars);
  48. break;
  49. }
  50. }
  51. }
  52. $router = new Router();
  53. $router->get('/user/{id:\d+}', function(Context $ctx, $next, $vars) {
  54. $ctx->body = "user={$vars['id']}";
  55. });
  56. // $route->post('/post-route', 'post_handler');
  57. $router->addRoute(['GET', 'POST'], '/test', function(Context $ctx, $next, $vars) {
  58. $ctx->body = "";
  59. });
  60. // 分组路由
  61. $router->addGroup('/admin', function (RouteCollector $router) {
  62. // handler :: (Context $ctx, $next, array $vars) -> void
  63. $router->addRoute('GET', '/do-something', 'handler');
  64. $router->addRoute('GET', '/do-another-thing', 'handler');
  65. $router->addRoute('GET', '/do-something-else', 'handler');
  66. });
  67. $app->υse($router->routes());

我们已经拥有了一个支持多方法 正则 参数匹配 分组功能的路由中间件。