--- layout: wiki wiki: laravel #项目名 date: 2023-12-28 16:56 categories: [Laravel] title: 解析路由 --- {%quot el:h2 解析路由%} 上面说到,请求经过中间件之后,最终调用`dispatchToRouter()`方法,接下来分析`dispatchToRouter()`方法的实现。 ```php protected function dispatchToRouter() { return function ($request) { // 将request绑定到容器中 $this->app->instance('request', $request); // 路由匹配 return $this->router->dispatch($request); }; } ``` ### 查看dispatch()方法 源码, ```php public function dispatch(Request $request) { // 将请求给Router类的currentRequest变量 $this->currentRequest = $request; // 继续看下面的dispatchToRoute()方法 return $this->dispatchToRoute($request); } public function dispatchToRoute(Request $request) { return $this->runRoute($request, $this->findRoute($request)); } ``` 先看`findRoute()`方法, ```php protected function findRoute($request) { // 查找匹配的路由,如果路由不存在则抛出NotFoundHttpException异常 $this->current = $route = $this->routes->match($request); // 绑定路由到容器中 $route->setContainer($this->container); // 将路由绑定到容器中 $this->container->instance(Route::class, $route); return $route; } # ----------------------------------------- // $this->routes 为RouteCollection实例 public function __construct(Dispatcher $events, Container $container = null) { $this->events = $events; $this->routes = new RouteCollection; $this->container = $container ?: new Container; } # ------------------------------------------- // match方法 public function match(Request $request) { // 获取对应请求方法的所有路由 $routes = $this->get($request->getMethod()); // First, we will see if we can find a matching route for this current request // method. If we can, great, we can just return it so that it can be called // by the consumer. Otherwise we will check for routes with another verb. $route = $this->matchAgainstRoutes($routes, $request); return $this->handleMatchedRoute($request, $route); } ``` #### 查看runRoute()方法 ```php protected function runRoute(Request $request, Route $route) { $request->setRouteResolver(function () use ($route) { return $route; }); // 触发RouteMatched事件 $this->events->dispatch(new RouteMatched($route, $request)); // 返回响应内容 return $this->prepareResponse($request, $this->runRouteWithinStack($route, $request) ); } ``` ##### runRouteWithinStack()方法 返回响应内容 ```php protected function runRouteWithinStack(Route $route, Request $request) { $shouldSkipMiddleware = $this->container->bound('middleware.disable') && $this->container->make('middleware.disable') === true; // 这里的中间件可以是全局中间件,也可以是路由中间件 $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route); // 这里又执行了一次在处理请求时的Pipeline类,只是最后传的匿名函数不同 // 最终返回响应内容给toResponse()方法 return (new Pipeline($this->container)) ->send($request) ->through($middleware) ->then(function ($request) use ($route) { return $this->prepareResponse( $request, $route->run() ); }); } #-------------------------------------------------------------------- // run方法 public function run() { $this->container = $this->container ?: new Container; try { /** * 判断是否是控制器方法 * 是则运行控制器的方法 */ if ($this->isControllerAction()) { /** * protected function runController() * { * return $this->controllerDispatcher()->dispatch( * $this, $this->getController(), $this->getControllerMethod() * ); * } */ return $this->runController(); } // 如果不是,则运行回调函数 return $this->runCallable(); } catch (HttpResponseException $e) { return $e->getResponse(); } } ``` ##### prepareResponse()方法 ```php # ----------------------------------------------------------- # prepareResponse()方法,第一个是请求对象,第二个是$this->runRouteWithinStack($route, $request)方法返回的响应内容 public function prepareResponse($request, $response) { return static::toResponse($request, $response); } // toResponse()方法 // 判断响应内容是那种类型,然后实例化对应的响应对象 public static function toResponse($request, $response) { if ($response instanceof Responsable) { $response = $response->toResponse($request); } if ($response instanceof PsrResponseInterface) { $response = (new HttpFoundationFactory)->createResponse($response); } elseif ($response instanceof Model && $response->wasRecentlyCreated) { $response = new JsonResponse($response, 201); } elseif ($response instanceof Stringable) { $response = new Response($response->__toString(), 200, ['Content-Type' => 'text/html']); } elseif (! $response instanceof SymfonyResponse && ($response instanceof Arrayable || $response instanceof Jsonable || $response instanceof ArrayObject || $response instanceof JsonSerializable || $response instanceof \stdClass || is_array($response))) { $response = new JsonResponse($response); } elseif (! $response instanceof SymfonyResponse) { $response = new Response($response, 200, ['Content-Type' => 'text/html']); } if ($response->getStatusCode() === Response::HTTP_NOT_MODIFIED) { $response->setNotModified(); } return $response->prepare($request); } ``` 最终`dispatchToRouter()`方法返回一个Response对象,然后执行`carry()`方法 ```php protected function carry() { return function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { try { // 省略... $carry = method_exists($pipe, $this->method) ? $pipe->{$this->method}(...$parameters) : $pipe(...$parameters); // 最终return handleCarry这个方法 // carry是返回的Response对象 return $this->handleCarry($carry); } catch (Throwable $e) { return $this->handleException($passable, $e); } }; }; } ``` ### 查看handleCarry()方法 上面内容跑完之后,最终返回的就是一个`Response`对象,然后响应对象调用`toResponse`方法,将`Request`对象从容器中取出传参 ```php protected function handleCarry($carry) { return $carry instanceof Responsable ? $carry->toResponse($this->getContainer()->make(Request::class)) : $carry; } ```