前言
本文主要給大家介紹的是關于Laravel路由模塊的相關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧。
備注:本文是基于Laravel 5.4版本的路由模塊代碼進行分析書寫;
模塊組成
下圖展示了路由模塊中各個文件的關系,并進行簡要說明;
剖析
服務提供者
看Laravel模塊,首先找ServiceProvider文件,這是模塊與IOC容器交互的入口,從這個文件,可以看出該模塊提供向系統提供了哪些服務;
public function register() { // 注冊路由管理,提供路由注冊,路由匹配的功能 $this->registerRouter(); // 注冊 Url 生成器實例 $this->registerUrlGenerator(); // 注冊跳轉器 $this->registerRedirector(); // 綁定 PSR-7 請求實現到 ServerRequestInterface 接口 $this->registerPsrRequest(); // 綁定 PSR-7 Response 實現到 ResponseInterface 接口 $this->registerPsrResponse(); // 注冊 ReponseFactory,提供各式各樣的 Response,比如視圖響應、Json響應、Jsonp響應、文件下載等 $this->registerResponseFactory(); }
路由管理
“路由管理”服務有以下元素需要了解:
- Route:路由;會記錄 Url、Http 動作、Action (路由要執行的具體對象,可能是 Closure,也可以是某個 Controller 中的方法),路由參數,路由參數的約束;
- RouteCollection:路由集,用來存儲所有Route對象的“盒子”;
- RouteGroup:路由組;只有路由注冊過程中會臨時用到;存儲一批路由公共的一些屬性,屬性包括domain、prefix、as、middleware、namespace、where;
- Resource:資源路由;資源路由是一套路由的統稱,包含列表(index)、顯示增加(create)、保存增加(store)、顯示詳情(show)、顯示編輯詳情(edit)、更新編輯(update)、刪除詳情(destory);同時可以通過調用only或except方法或參數的形式只生成部分路由;
- Action:路由要執行的對象;有兩種表現形式,一是Closure函數,二是類似
['uses' => 'FooController@method', 'as' => 'name']
這樣的字符串;對于不同的表現形式,路由在執行時會調用不同的處理;
注冊流程
在項目啟動后,會執行所有ServiceProvider的loadRoutes方法,也就是調用map方法,一般情況下map方法如下
public function map(Router $router){ require __DIR__.'/routes.php'; }
這時候,項目就會執行很多Route::get
、Route::post
、Route::group
方法;
當遇到Route::group方法時,會實例化一個RouteGroup對象,put進Router管理類的路由組棧頭部;而后當執行get、post這類具體的注冊路由方法時,會把當前路由組棧中所有組的屬性合并進新路由中,將新路由存儲在RouteCollection這個大盒子里;當Route::group的Closure執行完畢時,會把頭部的RouteGroup實例pull出去;
當執行Route::resource時,Router管理類會調用ResourceRegister類來完成批量注冊路由;
對于 Router::get這類注冊方法,Illuminate\Foudation\helpers提供了簡寫;
Router::get
簡化成 get,Router::post
簡化成 post,Router::put
簡化成 put,Router::patch
簡化成 patch,Router::delete
簡化成 delete,Router::resource
簡化成 resource,
至此,RouteCollection大盒子就存放了所有要注冊的路由;
request 請求匹配流程
首先,request請求會經過Foundation/Http/Kernel的handle方法,在這個方法中,請求會執行以下語句
$this->router->dispatch($request)
這里的$this->router
,就是Router管理類;dispatch方法如下
public function dispatch(Request $request) { $this->currentRequest = $request; return $this->dispatchToRoute($request); } public function dispatchToRoute(Request $request) { // 根據請求的 url 找到匹配的路由 $route = $this->findRoute($request); // 將路由綁定到請求上 $request->setRouteResolver(function () use ($route) { return $route; } // 觸發 RouteMatched 事件 $this->events->dispatch(new Events\RouteMatched($route, $request)); // 通過 Pipeline 流水線執行路由上綁定的中間件及對應的方法 $response = $this->runRouteWithinStack($route, $request); // 根據 request 請求設置 response 的響應頭 return $this->prepareResponse($request, $response); }
1、根據請求找匹配的路由