溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Laravel中如何使用路由模塊

發(fā)布時(shí)間:2021-07-19 14:37:39 來源:億速云 閱讀:131 作者:Leah 欄目:開發(fā)技術(shù)

這篇文章給大家介紹Laravel中如何使用路由模塊,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。

模塊組成

下圖展示了路由模塊中各個(gè)文件的關(guān)系,并進(jìn)行簡要說明;

Laravel中如何使用路由模塊

剖析

服務(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è)方法
redirectToresponse()->redirectTo(...)to方法
redirectToRouteresponse()->redirectToRoute(...)route方法
redirectToActionresponse()->redirectToAction(...)action方法
redirectGuestresponse()->redirectGuest(...)guest方法
redirectToIntendedresponse()->redirectToIntended(...)intended方法

關(guān)于Laravel中如何使用路由模塊就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(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)容。

AI