在路由中,你可以在分組中創(chuàng)建分組,來實現(xiàn)僅僅為父分組中的某些路由分配中間件。
Route::group(['prefix' => 'account', 'as' => 'account.'], function() {
Route::get('login', 'AccountController@login');
Route::get('register', 'AccountController@register');
Route::group(['middleware' => 'auth'], function() {
Route::get('edit', 'AccountController@edit');
});
});
你可以在分組中定義變量,來創(chuàng)建動態(tài)子域名分組,然后將這個變量傳遞給每一個子路由。
Route::domain('{username}.workspace.com')->group(function () {
Route::get('user/{id}', function ($username, $id) {
//
});
});
想知道 Auth::routes()
路由之后是什么?
從 Laravel 7 之后,它被分在一個單獨的包中,你可以查閱文件 /vendor/laravel/ui/src/AuthRouteMethods.php
。
public function auth()
{
return function ($options = []) {
// 鑒權(quán)路由……
$this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
$this->post('login', 'Auth\LoginController@login');
$this->post('logout', 'Auth\LoginController@logout')->name('logout');
// 注冊路由……
if ($options['register'] ?? true) {
$this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
$this->post('register', 'Auth\RegisterController@register');
}
// 重置密碼路由……
if ($options['reset'] ?? true) {
$this->resetPassword();
}
// 確認(rèn)密碼路由……
if ($options['confirm'] ?? class_exists($this->prependGroupNamespace('Auth\ConfirmPasswordController'))) {
$this->confirmPassword();
}
// 郵箱驗證路由……
if ($options['verify'] ?? false) {
$this->emailVerification();
}
};
}
Laravel 7 之前,請查閱 /vendor/laravel/framework/src/illuminate/Routing/Router.php
。
你可以像 Route::get('api/users/{user}', function (App\User $user) { … }
這樣來進行路由模型綁定,但不僅僅是 ID 字段,如果你想讓 {user}
是 username
,你可以把它放在模型中:
public function getRouteKeyName() {
return 'username';
}
在 Laravel 8 之前,這件事情是可選的。在 Laravel 8 中這將成為路由的標(biāo)準(zhǔn)語法。
你可以將控制器標(biāo)識為 類
:
Route::get('page', [\App\Http\Controllers\PageController::class, 'action']);
而不是
Route::get('page', 'PageController@action');
這樣,你就可以在 PhpStorm 中點擊 PageController 來跳轉(zhuǎn)到控制器定義,而不是手動去搜索它。
或者你想要讓路由的定義更簡潔,你可以在路由文件的開始提前引入控制器的類。
use App\Http\Controllers\PageController;
// 然后:
Route::get('page', [PageController::class, 'action']);
如果你想為未找到的路由指定其它邏輯,而不是直接顯示 404 頁面,你可以在路由文件的最后為其創(chuàng)建一個特殊的路由。
Route::group(['middleware' => ['auth'], 'prefix' => 'admin', 'as' => 'admin.'], function () {
Route::get('/home', 'HomeController@index');
Route::resource('tasks', 'Admin\TasksController');
});
// 一些其它的路由....
Route::fallback(function() {
return 'emmm...出錯了~';
});
我們可以在路由中使用 where
來直接驗證參數(shù)。一個典型的例子是,當(dāng)使用語言區(qū)域的參數(shù)來作為路由前綴時,像是 fr/blog
和 en/article/333
等,這時我們?nèi)绾蝸泶_保這兩個首字母沒有被用在其他語言呢?
routes/web.php
:
Route::group([
'prefix' => '{locale}',
'where' => ['locale' => '[a-zA-Z]{2}']
], function () {
Route::get('/', 'HomeController@index');
Route::get('article/{id}', 'ArticleController@show');
});
你可以使用 throttle:60,1
來限制一些 URL 在每分鐘內(nèi)最多被訪問 60 次。
Route::middleware('auth:api', 'throttle:60,1')->group(function () {
Route::get('/user', function () {
//
});
});
另外,你也可以為公開請求和登錄用戶分別配置:
// 游客最大 10 次,登錄用戶最大 60次
Route::middleware('throttle:10|60,1')->group(function () {
//
});
此外,你也可以使用數(shù)據(jù)庫字段 users.rate_limit
為一些特殊用戶設(shè)定此值。
Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
Route::get('/user', function () {
//
});
});
如果你在路由中使用數(shù)組傳入了其它參數(shù),這些鍵 / 值將會自動配對并且?guī)?URL 查詢參數(shù)中。
Route::get('user/{id}/profile', function ($id) {
//
})->name('profile');
$url = route('profile', ['id' => 1, 'photos' => 'yes']); // 結(jié)果: /user/1/profile?photos=yes
如果你有一組與某些功能相關(guān)的路由,你可以將它們放在一個特殊的文件 routes/XXXXX.php
中,然后在 routes/web.php
中使用 include
引入它。
Taylor Otwell 在 Laravel Breeze 中的例子:
?routes/auth.php
?
Route::get('/', function () {
return view('welcome');
});
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth'])->name('dashboard');
require __DIR__.'/auth.php';
然后,在 routes/auth.php
中:
use App\Http\Controllers\Auth\AuthenticatedSessionController;
use App\Http\Controllers\Auth\RegisteredUserController;
// ... 一些控制器
use Illuminate\Support\Facades\Route;
Route::get('/register', [RegisteredUserController::class, 'create'])
->middleware('guest')
->name('register');
Route::post('/register', [RegisteredUserController::class, 'store'])
->middleware('guest');
// ... 另外一些路由
但是,你應(yīng)該只在路由都各自具有相同的前綴 / 中間件配置時使用 include()
來引入路由,否則,更好的選擇是將他們分類在 app/Providers/RouteServiceProvider
中。
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
// ... 你的路由列在這后邊
});
}
當(dāng)你使用資源控制器,但希望變更 URL 謂詞以適應(yīng)非英語語言環(huán)境下的 SEO ,這樣在路由中就是 /crear
而非/create
,你可以使用 App\Providers\RouteServiceProvider
中的 Route::resourceVerbs()
配置。
public function boot()
{
Route::resourceVerbs([
'create' => 'crear',
'edit' => 'editar',
]);
// ...
}
當(dāng)使用資源路由時,你可以在 routes/web.php
中指定 ->names()
參數(shù),這樣一來,在整個 Laravel 項目中,瀏覽器中的 URL 前綴和路由名稱前綴可能會不同。
Route::resource('p', ProductController::class)->names('products');
這行代碼將會生成像 /p
, /p/{id}
, /p/{id}/edit
這樣的路由,但是你可以在代碼中使用 route('products.index')
, route('products.create')
等方式來調(diào)用它們。
你有沒有運行過 php artisan route:list
,然后發(fā)現(xiàn)這個列表又長,可讀性又很差。
另一個方法是:
?php artisan route:list --compact
?
這樣只會輸出 3 列,而非 6 列:只展示方法名、 URI 和方法。
+----------+---------------------------------+-------------------------------------------------------------------------+
| Method | URI | Action |
+----------+---------------------------------+-------------------------------------------------------------------------+
| GET|HEAD | / | Closure |
| GET|HEAD | api/user | Closure |
| POST | confirm-password | App\Http\Controllers\Auth\ConfirmablePasswordController@store |
| GET|HEAD | confirm-password | App\Http\Controllers\Auth\ConfirmablePasswordController@show |
| GET|HEAD | dashboard | Closure |
| POST | email/verification-notification | App\Http\Controllers\Auth\EmailVerificationNotificationController@store |
| POST | forgot-password | App\Http\Controllers\Auth\PasswordResetLinkController@store |
| GET|HEAD | forgot-password | App\Http\Controllers\Auth\PasswordResetLinkController@create |
| POST | login | App\Http\Controllers\Auth\AuthenticatedSessionController@store |
| GET|HEAD | login | App\Http\Controllers\Auth\AuthenticatedSessionController@create |
| POST | logout | App\Http\Controllers\Auth\AuthenticatedSessionController@destroy |
| POST | register | App\Http\Controllers\Auth\RegisteredUserController@store |
| GET|HEAD | register | App\Http\Controllers\Auth\RegisteredUserController@create |
| POST | reset-password | App\Http\Controllers\Auth\NewPasswordController@store |
| GET|HEAD | reset-password/{token} | App\Http\Controllers\Auth\NewPasswordController@create |
| GET|HEAD | verify-email | App\Http\Controllers\Auth\EmailVerificationPromptController@__invoke |
| GET|HEAD | verify-email/{id}/{hash} | App\Http\Controllers\Auth\VerifyEmailController@__invoke |
+----------+---------------------------------+-------------------------------------------------------------------------+
你還可以特別地指定所需要的列:
?php artisan route:list --columns=Method,URI,Name
?
+----------+---------------------------------+---------------------+
| Method | URI | Name |
+----------+---------------------------------+---------------------+
| GET|HEAD | / | |
| GET|HEAD | api/user | |
| POST | confirm-password | |
| GET|HEAD | confirm-password | password.confirm |
| GET|HEAD | dashboard | dashboard |
| POST | email/verification-notification | verification.send |
| POST | forgot-password | password.email |
| GET|HEAD | forgot-password | password.request |
| POST | login | |
| GET|HEAD | login | login |
| POST | logout | logout |
| POST | register | |
| GET|HEAD | register | register |
| POST | reset-password | password.update |
| GET|HEAD | reset-password/{token} | password.reset |
| GET|HEAD | verify-email | verification.notice |
| GET|HEAD | verify-email/{id}/{hash} | verification.verify |
+----------+---------------------------------+---------------------+
如果你使用了路由模型綁定,并且你認(rèn)為不會在綁定關(guān)系中使用急切加載,請你再想一想。
所以當(dāng)你用了這樣的路由模型綁定
public function show(Product $product) {
//
}
但是你有一個從屬關(guān)系,并且不能使用 $product->with('category')
急切加載嗎?
但實際上這是可以的,使用 ->load()
來加載關(guān)系。
public function show(Product $product) {
$product->load('category');
//
}
如果你使用了資源控制器,但是想要將 URL 謂詞變?yōu)榉怯⒄Z形式的,比如你想要西班牙語的 /crear
而不是 /create
,你可以使用 Route::resourceVerbs()
方法來配置。
public function boot()
{
Route::resourceVerbs([
'create' => 'crear',
'edit' => 'editar',
]);
//
}
在資源控制器中,你可以在 routes/web.php
中指定 ->names()
參數(shù),這樣 URL 前綴與路由前綴可能會不同
這樣會生成諸如 /p
, /p/{id}
, /p/{id}/edit
等等,但是你可以這樣調(diào)用它們:
Route::resource('p', \App\Http\Controllers\ProductController::class)->names('products');
更多建議: