1、执行上文管道中的then方法指定的闭包,路由的分发
2、在路由器中(Router类)找到请求($request 也就是经过全局中间件处理的请求)匹配的路由规则
3、说明路由规则的加载(会跳转到框架的boot过程),注意这部分是在处理请求之前完成的,因为一旦当我们开始处理请求,就意味着所有的路由都应该已经加载好了,供我们的请求进行匹配
4、执行请求匹配到的路由逻辑
5、生成响应,并发送给客户端
6、最后生命周期的结束
7、基本响应类的使用
前文说道,如果一个请求顺利通过了全局中间件那么就会调用管道then方法中传入的闭包
protected function sendRequestThroughRouter($request) { $this->app->instance('request', $request); Facade::clearResolvedInstance('request'); $this->bootstrap(); // 代码如下 return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) // 此方法将当前请求挂载到容器,然后执行路由器的分发 ->then($this->dispatchToRouter()); } protected function dispatchToRouter() { return function ($request) { $this->app->instance('request', $request); return $this->router->dispatch($request); }; }
查看Illuminate\Routing\Router::dispatch方法
public function dispatch(Request $request) { $this->currentRequest = $request; // 将请求分发到路由 // 跳转到dispatchToRoute方法 return $this->dispatchToRoute($request); } public function dispatchToRoute(Request $request) { // 先跳转到findRoute方法 return $this->runRoute($request, $this->findRoute($request)); } // 见名之意 通过给定的$request 找到匹配的路由 protected function findRoute($request) { // 跳转到Illuminate\Routing\RouteCollection::match方法 $this->current = $route = $this->routes->match($request); $this->container->instance(Route::class, $route); return $route; }
查看Illuminate\Routing\RouteCollection::match方法
/** * Find the first route matching a given request. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Routing\Route * * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException */ public function match(Request $request) { // 根据请求动作找到全局匹配的路由 // 可以自行打印下$routes $routes = $this->get($request->getMethod()); // 匹配路由 下面查看框架如何生成的路由规则!!! $route = $this->matchAgainstRoutes($routes, $request); if (! is_null($route)) { return $route->bind($request); } $others = $this->checkForAlternateVerbs($request); if (count($others) > 0) { return $this->getRouteForMethods($request, $others); } throw new NotFoundHttpException; }
下面说明框架如何加载的路由规则
Application::boot方法
// 主要逻辑是调用服务提供者的boot方法 array_walk($this->serviceProviders, function ($p) { $this->bootProvider($p); });
App\Providers\RouteServiceProvider::boot方法
public function boot() { // 调用父类Illuminate\Foundation\Support\Providers\RouteServiceProvider的boot方法 parent::boot(); }
Illuminate\Foundation\Support\Providers\RouteServiceProvider::boot方法
public function boot() { $this->setRootControllerNamespace(); if ($this->routesAreCached()) { $this->loadCachedRoutes(); } else { // 就看这个loadRoutes方法 $this->loadRoutes(); $this->app->booted(function () { // dd(get_class($this->app['router'])); $this->app['router']->getRoutes()->refreshNameLookups(); $this->app['router']->getRoutes()->refreshActionLookups(); }); } } /** * Load the application routes. * 看注释就知道我们来对了地方 * @return void */ protected function loadRoutes() { // 调用App\Providers\RouteServiceProvider的map方法 if (method_exists($this, 'map')) { $this->app->call([$this, 'map']); } }
App\Providers\RouteServiceProvider::map方法
public function map() { // 为了调试方便我注释掉了api路由 // $this->mapApiRoutes(); // 这两个都是加载路由文件 这里查看web.php $this->mapWebRoutes(); } protected function mapWebRoutes() { // 调用Router的__call方法 返回的是RouteRegistrar实例 Route::middleware('web') ->namespace($this->namespace) // 调用RouteRegistrar的namespace方法 触发__call魔术方法 // 依然是挂载属性 可自行打印 // Illuminate\Routing\RouteRegistrar {#239 ▼ // #router: Illuminate\Routing\Router {#34 ▶} // #attributes: array:2 [▼ // "middleware" => array:1 [▼ // 0 => "web" // ] // "namespace" => "App\Http\Controllers" // ] // #passthru: array:7 [▶] // #allowedAttributes: array:7 [▶] // #aliases: array:1 [▶] // } // 调用RouteRegistrar的group方法 ->group(base_path('routes/web.php')); }
Router::__call方法