您好,登錄后才能下訂單哦!
這篇文章給大家介紹Laravel中如何使用路由模塊,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
模塊組成
下圖展示了路由模塊中各個(gè)文件的關(guān)系,并進(jìn)行簡要說明;
剖析
服務(wù)提供者
看Laravel模塊,首先找ServiceProvider文件,這是模塊與IOC容器交互的入口,從這個(gè)文件,可以看出該模塊提供向系統(tǒng)提供了哪些服務(wù);
public function register() { // 注冊(cè)路由管理,提供路由注冊(cè),路由匹配的功能 $this->registerRouter(); // 注冊(cè) Url 生成器實(shí)例 $this->registerUrlGenerator(); // 注冊(cè)跳轉(zhuǎn)器 $this->registerRedirector(); // 綁定 PSR-7 請(qǐng)求實(shí)現(xiàn)到 ServerRequestInterface 接口 $this->registerPsrRequest(); // 綁定 PSR-7 Response 實(shí)現(xiàn)到 ResponseInterface 接口 $this->registerPsrResponse(); // 注冊(cè) ReponseFactory,提供各式各樣的 Response,比如視圖響應(yīng)、Json響應(yīng)、Jsonp響應(yīng)、文件下載等 $this->registerResponseFactory(); }
路由管理
“路由管理”服務(wù)有以下元素需要了解:
Route:路由;會(huì)記錄 Url、Http 動(dòng)作、Action (路由要執(zhí)行的具體對(duì)象,可能是 Closure,也可以是某個(gè) Controller 中的方法),路由參數(shù),路由參數(shù)的約束;
RouteCollection:路由集,用來存儲(chǔ)所有Route對(duì)象的“盒子”;
RouteGroup:路由組;只有路由注冊(cè)過程中會(huì)臨時(shí)用到;存儲(chǔ)一批路由公共的一些屬性,屬性包括domain、prefix、as、middleware、namespace、where;
Resource:資源路由;資源路由是一套路由的統(tǒng)稱,包含列表(index)、顯示增加(create)、保存增加(store)、顯示詳情(show)、顯示編輯詳情(edit)、更新編輯(update)、刪除詳情(destory);同時(shí)可以通過調(diào)用only或except方法或參數(shù)的形式只生成部分路由;
Action:路由要執(zhí)行的對(duì)象;有兩種表現(xiàn)形式,一是Closure函數(shù),二是類似['uses' => 'FooController@method', 'as' => 'name']
這樣的字符串;對(duì)于不同的表現(xiàn)形式,路由在執(zhí)行時(shí)會(huì)調(diào)用不同的處理;
注冊(cè)流程
在項(xiàng)目啟動(dòng)后,會(huì)執(zhí)行所有ServiceProvider的loadRoutes方法,也就是調(diào)用map方法,一般情況下map方法如下
public function map(Router $router){ require __DIR__.'/routes.php'; }
這時(shí)候,項(xiàng)目就會(huì)執(zhí)行很多Route::get
、Route::post
、Route::group
方法;
當(dāng)遇到Route::group方法時(shí),會(huì)實(shí)例化一個(gè)RouteGroup對(duì)象,put進(jìn)Router管理類的路由組棧頭部;而后當(dāng)執(zhí)行g(shù)et、post這類具體的注冊(cè)路由方法時(shí),會(huì)把當(dāng)前路由組棧中所有組的屬性合并進(jìn)新路由中,將新路由存儲(chǔ)在RouteCollection這個(gè)大盒子里;當(dāng)Route::group的Closure執(zhí)行完畢時(shí),會(huì)把頭部的RouteGroup實(shí)例pull出去;
當(dāng)執(zhí)行Route::resource時(shí),Router管理類會(huì)調(diào)用ResourceRegister類來完成批量注冊(cè)路由;
對(duì)于 Router::get這類注冊(cè)方法,Illuminate\Foudation\helpers提供了簡寫;
Router::get
簡化成 get,
Router::post
簡化成 post,
Router::put
簡化成 put,
Router::patch
簡化成 patch,
Router::delete
簡化成 delete,
Router::resource
簡化成 resource,
至此,RouteCollection大盒子就存放了所有要注冊(cè)的路由;
request 請(qǐng)求匹配流程
首先,request請(qǐng)求會(huì)經(jīng)過Foundation/Http/Kernel的handle方法,在這個(gè)方法中,請(qǐng)求會(huì)執(zhí)行以下語句
$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) { // 根據(jù)請(qǐng)求的 url 找到匹配的路由 $route = $this->findRoute($request); // 將路由綁定到請(qǐng)求上 $request->setRouteResolver(function () use ($route) { return $route; } // 觸發(fā) RouteMatched 事件 $this->events->dispatch(new Events\RouteMatched($route, $request)); // 通過 Pipeline 流水線執(zhí)行路由上綁定的中間件及對(duì)應(yīng)的方法 $response = $this->runRouteWithinStack($route, $request); // 根據(jù) request 請(qǐng)求設(shè)置 response 的響應(yīng)頭 return $this->prepareResponse($request, $response); }
1、根據(jù)請(qǐng)求找匹配的路由
`RouteCollection`根據(jù)請(qǐng)求的`http`動(dòng)作縮小要匹配的路由范圍;在篩選出來的這些路由中依次遍歷,找出第一個(gè)符合驗(yàn)證的路由(需要進(jìn)行較驗(yàn)的驗(yàn)證在`Route`中的`getValidators`方法中聲明);
2、將路由綁定到請(qǐng)求上
3、觸發(fā)RouteMatched事件
初始化的`Laravel`項(xiàng)目沒有對(duì)`RouteMatched`路由匹配事件進(jìn)行任何的監(jiān)聽器綁定,如有需要,可以自定義監(jiān)聽器,在模塊的`EventServiceProvider`中注冊(cè)該事件監(jiān)聽;這樣一旦請(qǐng)求匹配上某個(gè)路由,就可以執(zhí)行自定義方法了;
4、通過 Pipeline 流水線執(zhí)行路由上綁定的中間件及對(duì)應(yīng)的方法
在`runRouteWithinStack`方法中,系統(tǒng)會(huì)判斷是否需要執(zhí)行中間件,如果`IOC`容器中設(shè)置了`middleware.disable`的值為`true`,則需要執(zhí)行的中間件數(shù)組為空;否則會(huì)找到所有的中間件,并按照`middlewarePriority`對(duì)必要的一些中間件進(jìn)行排序調(diào)整;然后執(zhí)行`$route->run()`
方法;
5、根據(jù) request 請(qǐng)求設(shè)置 response 的響應(yīng)頭
項(xiàng)目中會(huì)用到的一些方法
獲取路由集合 app('router')->getRoutes()
獲取當(dāng)前的請(qǐng)求 $request = app('router')->getCurrentRequest()
獲取當(dāng)前請(qǐng)求所對(duì)應(yīng)的路由 $route = $request->route() 或 $route = app('router')->getCurrentRoute()
獲取當(dāng)前路由需要執(zhí)行的中間件 $middlewares = app('router')->gatherRouteMiddleware($route)
Url 生成器
Url 生成器是什么?
舉個(gè)例子,
$url = new UrlGenerator( $routes = new RouteCollection, $request = Request::create('http://www.foo.com/') ); $url->to('foo/bar'); // 輸出 http://www.foo.com/foo/bar
像這種基于當(dāng)前請(qǐng)求,生成指定路徑的Url;
這部分功能由兩個(gè)文件完成,一個(gè)是UrlGenerator.php,另一個(gè)是RouteUrlGenerator.php;UrlGenerator.php處理根據(jù)路徑名生成Url,RouteUrlGenerator.php處理根據(jù)路由生成Url;
列一些常用的使用:
根據(jù)路徑名生成
使用to方法,第一個(gè)參數(shù)為路徑,第二個(gè)參數(shù)是數(shù)組,implode后會(huì)接著路徑名,第三個(gè)參數(shù)決定用不用https
// 路徑名是 foo/bar,當(dāng)前請(qǐng)求的根路徑為 http://www.foo.com,所以輸出是 http://www.foo.com/foo/bar $url->to('foo/bar') // 路徑名是 foo/bar,當(dāng)前請(qǐng)求的根路徑為 http://www.foo.com,第三個(gè)參數(shù)決定 scheme 是 https,所以輸出是 https://www.foo.com/foo/bar $url->to('foo/bar', [], true) // 路徑名是 foo/bar,第二個(gè)參數(shù) 是補(bǔ)充路徑名,implode 后是 /baz/boom // 第三個(gè)參數(shù)決定 scheme 是 https,所以輸出是 https://www.foo.com/foo/bar/baz/boom $url->to('foo/bar', ['baz', 'boom'], true) // 路徑名是 foo/bar,查詢參數(shù)是 ?foo=bar ,補(bǔ)充路徑是 /baz,所以輸出是 https://www.foo.com/foo/bar/baz?foo=bar $url->to('foo/bar?foo=bar', ['baz'], true)
根據(jù)路由的 as 名生成
使用route方法,第一個(gè)參數(shù)為指定路由的 as 名,第二個(gè)參數(shù)是參數(shù)數(shù)組,第三個(gè)參數(shù)決定是否顯示根目錄(默認(rèn)為 true)
$route = new Route(['GET'], 'foo/bar', ['as' => 'foo']); $routes->add($route); // 輸出 'http://www.foo.com/foo/bar $url->route('foo'); // 第三個(gè)參數(shù)為 false,表示不顯示根目錄,于是輸出 /foo/bar $url->route('foo', [], false) // 路由中的 url 本身不帶參數(shù),則第二參數(shù)中所有關(guān)聯(lián)數(shù)組都將作為查詢參數(shù) // 輸出 /foo/bar?foo=bar $url->route('foo', ['foo' => 'bar'], false)
$route = new Route(['GET'], 'foo/bar/{baz}/breeze/{boom}', ['as' => 'bar']); $routes->add($route); // 路由上的 url 帶參數(shù),根據(jù)參數(shù)名找值;剩余多余的為查詢參數(shù); // 輸出 http://www.foo.com/foo/bar/otwell/breeze/taylor?fly=wall $url->route('bar', ['boom' => 'taylor', 'baz' => 'otwell', 'fly' => 'wall']); // 路由上的 url 帶參數(shù),找不到對(duì)應(yīng)的參數(shù)值,則按順序作值;剩余多余的為查詢參數(shù); // 輸出 http://www.foo.com/foo/bar/taylor/breeze/otwell?fly=wall $url->route('bar', ['taylor', 'otwell', 'fly' => 'wall']);
根據(jù)路由的 action 名生成
使用action方法,第一個(gè)參數(shù)為指定路由的 action 名,第二個(gè)參數(shù)是參數(shù)數(shù)組,第三個(gè)參數(shù)決定是否顯示根目錄(默認(rèn)為 true)
$route = new Route(['GET'], 'foo/bam', ['controller' => 'foo@bar']); $routes->add($route); // 輸出 http://www.foo.com/foo/bam $url->action('foo@bar');
$route = new Route(['GET'], 'foo/invoke', ['controller' => 'InvokableActionStub']); $routes->add($route); // 輸出 http://www.foo.com/foo/invoke $url->action('InvokableActionStub');
設(shè)置全局默認(rèn)參數(shù)
$url->defaults(['locale' => 'en']); $route = new Route(['GET'], 'foo', ['as' => 'defaults', 'domain' => '{locale}.example.com', function() {}]); // 路由 url 有參數(shù),但沒有傳參數(shù)值,則會(huì)找全局默認(rèn)參數(shù)值;輸出 http://en.example.com/foo $url->route('defaults');
設(shè)置全局命名空間
這樣調(diào)用的時(shí)候,不用在 action 上省略這部分命名空間
// 設(shè)置全局命名空間 $url->setRootControllerNamespace('namespace'); // 配置添加路由 $route = new Route(['GET'], 'foo/bar', ['controller' => 'namespace\foo@bar']); $routes->add($route); $route = new Route(['GET'], 'foo/invoke', ['controller' => 'namespace\InvokableActionStub']); $routes->add($route); // 輸出 http://www.foo.com/foo/bar; action 的值省略 namespace 這個(gè)命名空間 $url->action('foo@bar'); // 輸出 http://www.foo.com/foo/invoke; action 的值省略 namespace 這個(gè)命名空間 $url->action('InvokableActionStub'); // 配置添加路由 $route = new Route(['GET'], 'something/else', ['controller' => 'something\foo@bar']); $routes->add($route); // 輸出 http://www.foo.com/something/else; action 的最前面加了 `\`,全局命名空間下調(diào)用 $url->action('\something\foo@bar');
跳轉(zhuǎn)器
跳轉(zhuǎn)器內(nèi)部提供了以下跳轉(zhuǎn);
home
通過調(diào)用app('redirect')->home()
會(huì)跳轉(zhuǎn)至根目錄下\;
public function home($status = 302)
back
通過調(diào)用app('redirect')->back()
會(huì)跳轉(zhuǎn)至上一次訪問頁面;或者全局幫助函數(shù)back()
也可以;
public function back($status = 302, $headers = [], $fallback = false)
第三個(gè)參數(shù)表示,如果沒有前一次訪問請(qǐng)求,訪問哪個(gè)頁面,具體源碼如下:
if ($url) { return $url; } elseif ($fallback) { return $this->to($fallback); } else { return $this->to('/'); }
refresh
通過調(diào)用app('redirect')->refresh()
會(huì)刷新當(dāng)前訪問頁面;
public function refresh($status = 302, $headers = [])
to
通過調(diào)用app('redirect')->to('path')
會(huì)跳轉(zhuǎn)至指定路徑頁面;或者全局幫助函數(shù)redirect('path')
也可以;
這里的 path 路徑是不包含根目錄的,例如(foo/bar);
public function to($path, $status = 302, $headers = [], $secure = null)
第四個(gè)參數(shù)表示是否使用https;
away
通過調(diào)用app('redirect')->away('path')
會(huì)跳轉(zhuǎn)至指定路徑頁面;
這里的 path 路徑是包含根目錄的,例如(http://xx.com/foo/bar);
public function away($path, $status = 302, $headers = [])
secure
通過調(diào)用app('redirect')->secure('path')
會(huì)跳轉(zhuǎn)至指定路徑頁面;這里的path路徑是不包含根目錄的;
public function secure($path, $status = 302, $headers = [])
其本質(zhì)是調(diào)用了to方法
return $this->to($path, $status, $headers, true);
route
通過調(diào)用app('redirect')->route('route_as_name')
,根據(jù)路由的as名會(huì)跳轉(zhuǎn)至與路由一致的url路徑頁;
public function route($route, $parameters = [], $status = 302, $headers = [])
action
通過調(diào)用app('redirect')->action('route_action')
,根據(jù)路由的action名會(huì)跳轉(zhuǎn)至與路由一致的url路徑頁;
public function action($action, $parameters = [], $status = 302, $headers = [])
guest
跳到指定的路徑頁的同時(shí),將當(dāng)前url存放至session中,鍵名為url.intended;
public function guest($path, $status = 302, $headers = [], $secure = null)
intended
跳轉(zhuǎn)至session中鍵名為url.intended的值所對(duì)應(yīng)的Url;如果不存在,則跳轉(zhuǎn)至第一個(gè)參數(shù)所傳的值;
public function intended($default = '/', $status = 302, $headers = [], $secure = null)
響應(yīng)工廠(ResponseFactory)
ResponseFactory文件提供了兩部分 API,分別是與響應(yīng)類型相關(guān)和與跳轉(zhuǎn)相關(guān);
響應(yīng)
response()
會(huì)返回ResponseFactory實(shí)例;
視圖響應(yīng)
response()->view('hello', $data, 200);
Jsop響應(yīng)
response()->json(['name' => 'Abigail', 'state' => 'CA']);
Jsonp響應(yīng)
response()->json(['name' => 'Abigail', 'state' => 'CA'])->withCallback($request->input('callback'));
文件響應(yīng)
直接在瀏覽器顯示文件,而不是下載,例如圖片或PDF;file方法第一參數(shù)為文件路徑,第二參數(shù)選填為頭信息數(shù)組;
response()->file($pathToFile, $headers);
文件下載
download方法第一參數(shù)為文件路徑,第二參數(shù)選填為文件名,第三參數(shù)選填為頭信息數(shù)組;
return response()->download($pathToFile, $name, $headers);
跳轉(zhuǎn)
這里的跳轉(zhuǎn)方法,其實(shí)調(diào)用的還是跳轉(zhuǎn)器中的方法,不過是在暴露更多的接口,方便調(diào)用與使用;
方法名 | 調(diào)用 | 實(shí)際調(diào)用的是跳轉(zhuǎn)器中的哪個(gè)方法 |
---|---|---|
redirectTo | response()->redirectTo(...) | to方法 |
redirectToRoute | response()->redirectToRoute(...) | route方法 |
redirectToAction | response()->redirectToAction(...) | action方法 |
redirectGuest | response()->redirectGuest(...) | guest方法 |
redirectToIntended | response()->redirectToIntended(...) | intended方法 |
關(guān)于Laravel中如何使用路由模塊就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。