鍍金池/ 教程/ PHP/ HTTP 路由
門面
Laravel Homestead
安裝及配置
測試
HTTP 中間件
加密
升級指南
幫助函數(shù)
應用目錄結(jié)構(gòu)
集合
新手入門指南-簡單任務管理系統(tǒng)
任務調(diào)度
查詢構(gòu)建器
視圖
驗證
Laravel Cashier(訂購&支付&發(fā)票)
本地化
隊列
調(diào)整器
分頁
文件系統(tǒng)/云存儲
貢獻代碼
哈希
HTTP 控制器
緩存
遷移
HTTP 請求
Laravel Elixir
發(fā)行版本說明
Envoy 任務運行器(SSH任務)
序列化
Session
起步
帶用戶功能的任務管理系統(tǒng)
起步
用戶授權(quán)
郵件
事件
填充數(shù)據(jù)
HTTP 路由
服務提供者
Blade 模板引擎
包開發(fā)
用戶認證
Artisan 控制臺
HTTP 響應
集合
服務容器
關(guān)聯(lián)關(guān)系
一次請求的生命周期
契約
Redis
錯誤&日志

HTTP 路由

1、基本路由

大部分路由都定義在被 App\Providers\RouteServiceProvider 類載入的 app/Http/routes.php 文件中。 最基本的 Laravel 路由接收一個 URI 和一個閉包:

Route::get('/', function () {
    return 'Hello World';
});

Route::post('foo/bar', function () {
    return 'Hello World';
});

Route::put('foo/bar', function () {
    //
});

Route::delete('foo/bar', function () {
    //
});

為多個動作注冊路由 有時候需要注冊一個路由來響應多個不同的 HTTP 動作,你可以使用 Route 門面的 match 方法來實現(xiàn):

Route::match(['get', 'post'], '/', function () {
    return 'Hello World';
});

或者,還可以使用 any 方法注冊一個路由響應所有 HTTP 動作:

Route::any('foo', function () {
    return 'Hello World';
});

生成路由對應的 URLs 可以使用幫助函數(shù) url 來生成路由對應的 URLs:

$url = url('foo');

2、路由參數(shù)

2.1 必選參數(shù)

有時我們需要在路由中捕獲 URI 片段,比如,如果想要從 URL 中捕獲用戶 ID,可以通過如下方式定義路由參數(shù):

Route::get('user/{id}', function ($id) {
    return 'User '.$id;
});

可以按需要定義在路由中定義多個路由參數(shù):

Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
    //
});

路由參數(shù)總是通過花括號進行包裹,參數(shù)在路由被執(zhí)行時會被傳遞到路由的閉包。 注意:路由參數(shù)不能包含’-‘字符,需要的話可以使用_替代。

2.2 可選參數(shù)

有時候可能需要指定路由參數(shù),并且使得該路由參數(shù)是可選的,可以通過在參數(shù)名后加一個?來標記:

Route::get('user/{name?}', function ($name = null) {
    return $name;
});

Route::get('user/{name?}', function ($name = 'John') {
    return $name;
});

2.3 正則約束

可以使用路由實例上的 where 方法來約束路由參數(shù)的格式。where 方法接收參數(shù)名和一個正則表達式來定義該參數(shù)如何被約束:

Route::get('user/{name}', function ($name) {
    //
})->where('name', '[A-Za-z]+');

Route::get('user/{id}', function ($id) {
    //
})->where('id', '[0-9]+');

Route::get('user/{id}/{name}', function ($id, $name) {
    //
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

2.3.1 全局約束

如果想要路由參數(shù)在全局范圍內(nèi)被給定正則表達式約束,可以使用 pattern 方法。可以在 RouteServiceProvider 類的 boot 方法中定義約束模式:

/**
 * 定義路由模型綁定,模式過濾器等
 *
 * @param  \Illuminate\Routing\Router  $router
 * @return void
 * @translator  http://laravelacademy.org
 */
public function boot(Router $router){
    $router->pattern('id', '[0-9]+');
    parent::boot($router);
}

一旦模式被定義,將會自動應用到所有包含該參數(shù)名的路由中。 擴展閱讀:實例教程——HTTP 路由實例教程(一)—— 基本使用及路由參數(shù)

3、命名路由

命名路由使生成 URLs 或者重定向到指定路由變得很方便,在定義路由時指定路由名稱,然后使用數(shù)組鍵 as 指定路由別名:

Route::get('user/profile', ['as' => 'profile', function () {
    //
}]);

還可以為控制器動作指定路由名稱:

Route::get('user/profile', [
    'as' => 'profile', 'uses' => 'UserController@showProfile'
]);

3.1 路由分組 & 命名路由

如果你在使用路由分組,可以在路由分組屬性數(shù)組中指定 as 關(guān)鍵字來為分組中的路由設(shè)置一個共用的路由名前綴:

Route::group(['as' => 'admin::'], function () {
    Route::get('dashboard', ['as' => 'dashboard', function () {
        // 路由被命名為 "admin::dashboard"
    }]);
});

3.2 為命名路由生成 URLs

一旦你為給定路由分配了名字,通過 route 函數(shù)生成 URLs 時就可以使用路由名字:

$url = route('profile');
$redirect = redirect()->route('profile');

如果路由定義了參數(shù),可以將路由參數(shù)作為第二個參數(shù)傳遞給 route 函數(shù)。給定的路由參數(shù)將會自動插入 URL 中:

Route::get('user/{id}/profile', ['as' => 'profile', function ($id) {
    //
}]);
$url = route('profile', ['id' => 1]);

4、路由分組

路由分組允許我們在多個路由中共享路由屬性,比如中間件和命名空間等,這樣的話一大波共享屬性的路由就不必再各自定義這些屬性。共享屬性以數(shù)組的形式被作為第一個參數(shù)傳遞到 Route::group 方法中。 想要了解更多路由分組,我們希望通過幾個簡單的應用實例來展示其特性。

4.1 中間件

要分配中間件給分組中的所有路由,可以在分組屬性數(shù)組中使用 middleware 鍵。中間件將會按照數(shù)組中定義的順序依次執(zhí)行:

Route::group(['middleware' => 'auth'], function () {
    Route::get('/', function ()    {
        // 使用 Auth 中間件
    });

    Route::get('user/profile', function () {
        // 使用 Auth 中間件
    });
});

4.2 命名空間

另一個通用的例子是路由分組分配同一個 PHP 命名空間給多個控制器,可以在分組屬性數(shù)組中使用 namespace 參數(shù)來指定分組中控制器的命名空間:

Route::group(['namespace' => 'Admin'], function(){
    // 控制器在 "App\Http\Controllers\Admin" 命名空間下

    Route::group(['namespace' => 'User'], function()
    {
        // 控制器在 "App\Http\Controllers\Admin\User" 命名空間下
    });
});

默認情況下,RouteServiceProvider 包含 routes.php 并指定其所在命名空間,因此,我們只需要指定命名空間的 App\Http\Controllers 之后的一部分。

4.3 子域名路由

路由分組還可以被用于子域名路由通配符,子域名可以像 URIs 一樣被分配給路由參數(shù),從而允許捕獲子域名的部分用于路由或者控制器,子域名可以通過分組屬性數(shù)組中的 domain 鍵來指定:

Route::group(['domain' => '{account}.myapp.com'], function () {
    Route::get('user/{id}', function ($account, $id) {
        //
    });
});

4.4 路由前綴

屬性 prefix 可以用來為分組中每個給定 URI 添加一個前綴,比如,你想要為所有路由 URIs 前面添加前綴 admin

Route::group(['prefix' => 'admin'], function () {
    Route::get('users', function ()    {
        // 匹配 "/admin/users" URL
    });
});

你還可以使用 prefix 參數(shù)為分組路由指定公共參數(shù):

Route::group(['prefix' => 'accounts/{account_id}'], function () {
    Route::get('detail', function ($account_id)    {
        // 匹配 accounts/{account_id}/detail URL
    });
});

擴展閱讀:實例教程——HTTP 路由實例教程(二)—— 路由命名和路由分組

5、防止 CSRF 攻擊

5.1 簡介

Laravel 使得防止應用遭到跨站請求偽造攻擊變得簡單??缯菊埱髠卧焓且环N通過偽裝授權(quán)用戶的請求來利用授信網(wǎng)站的惡意漏洞。 Laravel 自動為每一個被應用管理的有效用戶 Session 生成一個 CSRF“令牌”,該令牌用于驗證授權(quán)用戶和發(fā)起請求者是否是同一個人。想要生成包含 CSRF 令牌的隱藏輸入字段,可以使用幫助函數(shù) csrf_field 來實現(xiàn):

<?php echo csrf_field(); ?>

幫助函數(shù) csrf_field 生成如下 HTML:

<input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">

當然還可以使用 Blade 模板引擎提供的方式:

{!! csrf_field() !!}

你不需要了解在 POST、PUT 或者 DELETE 請求時 CSRF 令牌是如何進行驗證的,HTTP 中間件VerifyCsrfToken 會為我們做這項工作:將請求中輸入的 token 值和 session 中的存儲的作對比。

5.2 從 CSRF 保護中排除 URIs

有時候我們想要從 CSRF 保護中排除一些 URIs,比如,如果你在使用 Stripe 來處理支付并用到他們的 webhook 系統(tǒng),這時候你就需要從 Laravel 的 CSRF 保護中排除 webhook 處理器路由。 你可以通過在 VerifyCsrfToken 中間件中將要排除的 URIs 添加到 $except屬性:

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;

class VerifyCsrfToken extends BaseVerifier
{
    /**
     *從 CSRF 驗證中排除的 URL
     *
     * @var array
     */
    protected $except = [
        'stripe/*',
    ];
}

5.3 X-CSRF-Token

除了將 CSRF 令牌作為一個 POST 參數(shù)進行檢查,Laravel 的 VerifyCsrfToken 中間件還會檢查 X-CSRF-TOKEN 請求頭,你可以將令牌保存在”meta”標簽中:

<meta name="csrf-token" content="{{ csrf_token() }}">

創(chuàng)建完這個 meta 標簽后,就可以在 js 庫如 jQuery 中添加該令牌到所有請求頭,這為基于 AJAX 的應用提供了簡單、方便的方式來避免 CSRF 攻擊:

$.ajaxSetup({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        }
});

5.4 X-XSRF-Token

Laravel 還將 CSRF 令牌保存到了名為 XSRF-TOKEN 的 cookie 中,你可以使用該 cookie 值來設(shè)置 X-XSRF-TOKEN 請求頭。一些 JavaScript 框架,比如 Angular,將會為你自動進行設(shè)置,基本上你不太會手動設(shè)置這個值。

擴展閱讀:實例教程——HTTP 路由實例教程(三)—— CSRF 攻擊原理及其防護

6、路由模型綁定

Laravel 路由模型綁定為注入類實例到路由提供了方便,例如,你可以將匹配給定 ID 的整個 User 類實例注入到路由中,而不是直接注入用戶 ID。

首先,使用路由的 model 方法為給定參數(shù)指定一個類,你應該在 RouteServiceProvider::boot 方法中定義模型綁定:

綁定參數(shù)到模型

public function boot(Router $router)
{
    parent::boot($router);
    $router->model('user', 'App\User');
}

接下來,定義一個包含{user}參數(shù)的路由:

$router->get('profile/{user}', function(App\User $user) {
    //
});

由于我們已經(jīng)綁定了{user}參數(shù)到 App\User 模型,一個 User 實例將會被注入到路由中。也就是說,如果請求 URL 是 profile/1,那么相應的將會注入 ID 為 1 的 User 實例到路由中。 注:如果在匹配模型實例的時候在數(shù)據(jù)庫中找不到對應記錄,那么就會自動拋出404異常。

如果你想要指定自己的“not found”行為,可以傳遞一個閉包作為第三個參數(shù)到 model 方法:

$router->model('user', 'App\User', function() {
    throw new NotFoundHttpException;
});

如果你想要使用自己的路由模型綁定解決方案,應該使用 Route::bind 方法,這樣的話傳遞到 bind 方法的閉包將會接受 URI 中的參數(shù)值,然后返回你想要注入到路由的類實例:

$router->bind('user', function($value) {
    return App\User::where('name', $value)->first();
});

7、表單方法偽造

HTML 表單不支持 PUT、PATCH 或者 DELETE 動作,因此,當定義被 HTML 表單調(diào)用的 PUT、PATCHDELETE 路由時,需要添加一個隱藏的_method 字段到給表單中,其值被用作 HTTP 請求方法名:

<form action="/foo/bar" method="POST">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>

8、拋出 404 錯誤

有兩者方法手動從路由觸發(fā) 404 錯誤。 第一種,使用幫助函數(shù) abort,abort 函數(shù)會拋出一個指定狀態(tài)碼的 Symfony\Component\HttpFoundation\Exception\HttpException

abort(404);

第二種,手動拋出 Symfony\Component\HttpKernel\Exception\NotFoundHttpException.的實例。

更多關(guān)于處理 404 異常的信息以及如何自定義視圖顯示這些錯誤信息,請查看錯誤文檔一節(jié)。

上一篇:填充數(shù)據(jù)下一篇:起步