Laravel路由
# 基本使用
# 请求方式
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
// 注册响应多个请求方式的路由
Route::match(['get', 'post'], '/', function () {
//
});
// 响应所有请求方式
Route::any('/', function () {
//
});
2
3
4
5
6
7
8
9
10
11
12
13
14
# 路由参数
# 必填参数
使用{}
定义路由参数
Route::get('/user/{id}', function ($id) {
return 'User '.$id;
});
// 定义多个参数
Route::get('/posts/{post}/comments/{comment}', function ($postId, $commentId) {
//
});
2
3
4
5
6
7
8
# 可选参数
在参数后面加?
来标记可选参数,必须给可选参数指定默认值。
Route::get('/user/{name?}', function ($name = null) {
return $name;
});
Route::get('/user/{name?}', function ($name = 'John') {
return $name;
});
2
3
4
5
6
7
# 正则表达式约束
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
4
5
6
7
8
9
10
11
12
一些常用的约束帮助方法
Route::get('/user/{id}/{name}', function ($id, $name) {
//
})->whereNumber('id')->whereAlpha('name');
Route::get('/user/{name}', function ($name) {
//
})->whereAlphaNumeric('name');
Route::get('/user/{id}', function ($id) {
//
})->whereUuid('id');
2
3
4
5
6
7
8
9
10
11
# 全局约束
如果你希望某个具体的路由参数都遵循同一个正则表达式的约束,就使用 pattern
方法。你应该在 App\Providers\RouteServiceProvider
类的 boot
方法中定义这些:
/**
* 定义你的路由模型绑定, pattern 过滤器等
*
* @return void
*/
public function boot()
{
Route::pattern('id', '[0-9]+');
}
2
3
4
5
6
7
8
9
一旦定义好之后,便会自动应用这些规则到所有使用该参数名称的路由上:
Route::get('/user/{id}', function ($id) {
// 只有在 id 为数字时才执行...
});
2
3
# 重定向
- 参数一:要进行跳转的路由
- 参数二:要跳转到的路由
- 参数三:返回的状态码,默认是 302
Route::redirect('/here', '/there');
Route::redirect('/here', '/there', 301);
2
3
直接使用 Route::permanentRedirect
返回 301
状态码
Route::permanentRedirect('/here', '/there');
注意
在重定向路由中使用路由参数时,以下参数由 Laravel 保留,不能使用: destination
和 status
.
# 视图路由
- 参数一:路由地址
- 参数二:视图
- 参数三:传递给视图的数据
Route::view('/welcome', 'welcome');
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
2
3
注意
当在图路由使用路线参数,下面的参数是由 Laravel 保留,不能使用: view
, data
, status
, 和 headers
.
禁止:Route::view('/welcome/{status}')
# 资源路由
Route::resource('posts','PostsController');
// 资源路由器只允许指定动作通过
Route::resource('photo', 'PhotoController',['only' => ['index', 'show']]);
Route::resource('photos', PhotoController::class)->only([
'index', 'show'
]);
// 资源路由器排除掉某些方法
Route::resource('photo', 'PhotoController',['except' => ['update', 'destroy']]);
Route::resource('photos', PhotoController::class)->except([
'create', 'store', 'update', 'destroy'
]);
// 批量注册资源路由
Route::resources(['foo' => 'FooController', 'bar' => 'BarController'])
Route::resources(['foo' => 'FooController', 'bar' => 'BarController'], ['only' => ['index', 'show']])
Route::resources(['foo' => 'FooController', 'bar' => 'BarController'], ['except' => ['update', 'destroy']])
2
3
4
5
6
7
8
9
10
11
12
13
14
15
资源控制器操作处理
请求方式 | 请求地址 | 控制器 | 路由名称 |
---|---|---|---|
GET | /photos | index | photos.index |
GET | /photos/create | create | photos.create |
POST | /photos | store | photos.store |
GET | /photos/{photo} | show | photos.show |
GET | /photos/{photo}/edit | edit | photos.edit |
PUT/PATCH | /photos/{photo} | update | photos.update |
DELETE | /photos/{photo} | destroy | photos.destroy |
# Api 资源路由
自动排除掉 create 和 edit 两个路由
Route::apiResources([
'photos' => PhotoController::class,
'posts' => PostController::class,
]);
2
3
4
# 嵌套资源
use App\Http\Controllers\PhotoCommentController;
Route::resource('photos.comments', PhotoCommentController::class);
2
3
使用 /photos/{photo}/comments/{comment}
来访问
# CSRF 保护
指向 web 路由文件中定义的 POST
, PUT
, PATCH
, 或 DELETE
路由的任何 HTML 表单都应该包含一个 CSRF
令牌字段,否则,这个请求将会被拒绝。
<form method="POST" action="/profile">
@csrf
...
</form>
2
3
4
# 浅层嵌套
通常,并不完全需要在 URI 中同时拥有父 ID 和子 ID,因为子 ID 已经是唯一的标识符。当使用唯一标识符(如自动递增的主键)来标识 URL 中的模型时,可以选择使用「浅嵌套」的方式定义路由:
use App\Http\Controllers\CommentController;
Route::resource('photos.comments', CommentController::class)->shallow();
2
3
上面的路由定义方式会定义以下路由:
请求方式 | 请求地址 | 控制器 | 路由名称 |
---|---|---|---|
GET | /photos/{photo}/comments | index | photos.comments.index |
GET | /photos/{photo}/comments/create | create | photos.comments.create |
POST | /photos/{photo}/comments | store | photos.comments.store |
GET | /comments/{comment} | show | comments.show |
GET | /comments/{comment}/edit | edit | comments.edit |
PUT/PATCH | /comments/{comment} | update | comments.update |
DELETE | /comments/{comment} | destroy | comments.destroy |
# 命名资源路由
use App\Http\Controllers\PhotoController;
Route::resource('photos', PhotoController::class)->names([
'create' => 'photos.build'
]);
2
3
4
5
# 命名资源路由参数
use App\Http\Controllers\AdminUserController;
Route::resource('users', AdminUserController::class)->parameters([
'users' => 'admin_user'
]);
// /users/{admin_user}
2
3
4
5
6
7
# 路由命名
路由命名可以方便地为指定路由生成 URL 或者重定向。通过在路由定义上链式调用 name
方法可以指定路由名称:
Route::get(
'/user/profile',
[UserProfileController::class, 'show']
)->name('profile');
2
3
4
注意
路由命名必须是唯一的
# 生成 URL
// 生成链接...
$url = route('profile');
// 生成重定向...
return redirect()->route('profile');
Route::get('/user/{id}/profile', function ($id) {
//
})->name('profile');
// 在第二个参数中传递路由参数
$url = route('profile', ['id' => 1]);
// /user/1/profile
Route::get('/user/{id}/profile', function ($id) {
//
})->name('profile');
// 不存在路由参数中的将自动添加在查询字符串当中
$url = route('profile', ['id' => 1, 'photos' => 'yes']);
// /user/1/profile?photos=yes
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 路由分组
# 中间件
Route::middleware(['first', 'second'])->group(function () {
Route::get('/', function () {
// Uses first & second middleware...
});
Route::get('/user/profile', function () {
// Uses first & second middleware...
});
});
2
3
4
5
6
7
8
9
# 子域名路由
Route::domain('{account}.example.com')->group(function () {
Route::get('user/{id}', function ($account, $id) {
//
});
});
2
3
4
5
注意
为了确保子域路由是可以访问的,你应该在注册根域路由之前注册子域路由。这将防止根域路由覆盖具有相同 URI 路径的子域路由。
# 路由前缀
Route::prefix('admin')->group(function () {
Route::get('/users', function () {
// Matches The "/admin/users" URL
});
});
2
3
4
5
# 路由名称前缀
Route::name('admin.')->group(function () {
Route::get('/users', function () {
// Route assigned name "admin.users"...
})->name('users');
});
2
3
4
5
# 备选路由
使用Route::fallback
方法,你可以定义一个路由,当没有其他路由与传入请求匹配时将执行该路由。
通常,未处理的请求将通过你的应用程序的异常处理程序自动渲染『404』页面。
但是,由于通常会在 route/web.php
文件中定义 fallback
路由,因此 web 中间件组中的所有中间件都将应用于该路由。
你可以根据需要随意向此路由添加其他中间件:
Route::fallback(function () {
//
});
2
3
注意
备选路由应始终是你应用程序注册的最后一个路由。
# 限流
# 定义限流器
定义在 RouteServiceProvider
类的 configureRateLimiting
方法中。
限流器可以使用 RateLimiter
门面的 for
方法定义。
该 for
方法接受一个速率限制器名称和一个闭包会返回限制配置,该配置可以应用于分配了该限流器的路由。
限制配置是 Illuminate\Cache\RateLimiting\Limit
类的实例。
这个类包含有用的『builder 』方法,以便于你可以快速定义你的限制。
限流器名称可以是你希望的任何字符串:
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
/**
* 为应用程序配置限流器。
*
* @return void
*/
protected function configureRateLimiting()
{
RateLimiter::for('global', function (Request $request) {
return Limit::perMinute(1000);
});
}
2
3
4
5
6
7
8
9
10
11
12
13
14
如果传入的请求超出了指定的限流,一个带有 429 HTTP
状态码的响应将自动通过 Laravel 返回。
如果你想定义应当由一个限流返回的你自己的响应,你可以使用 response
方法:
RateLimiter::for('global', function (Request $request) {
return Limit::perMinute(1000)->response(function () {
return response('Custom response...', 429);
});
});
2
3
4
5
由于限流器回调接收传入的 HTTP 请求实例,你可以基于传入的请求或经过身份验证的用户动态构建适当的限流:
RateLimiter::for('uploads', function (Request $request) {
return $request->user()->vipCustomer()
? Limit::none()
: Limit::perMinute(100);
});
2
3
4
5
# 分段限流
有时,你可能希望根据某些任意值分段限流。例如,你可能希望允许用户在每个 IP 地址上每分钟访问给定路由 100 次。要实现这点,你可以在构建你的限流时使用 by
方法:
RateLimiter::for('uploads', function (Request $request) {
return $request->user()->vipCustomer()
? Limit::none()
: Limit::perMinute(100)->by($request->ip());
});
2
3
4
5
# 多重限流
如果需要,你可以返回一个给定限流器配置的限流数组。每个限流将根据它们在数组中放置的顺序对路由进行评估:
RateLimiter::for('login', function (Request $request) {
return [
Limit::perMinute(500),
Limit::perMinute(3)->by($request->input('email')),
];
});
2
3
4
5
6
# 路由使用限流
限流器可以使用 throttle
中间件 被系到路由或路由组上。此 throttle
中间件接受你希望分配给路由的限流器名称:
Route::middleware(['throttle:uploads'])->group(function () {
Route::post('/audio', function () {
//
});
Route::post('/video', function () {
//
});
});
2
3
4
5
6
7
8
9
通常, throttle
中间件会映射到 Illuminate\Routing\Middleware\ThrottleRequests
类。
此映射在应用程序的 HTTP
内核 (App\Http\Kernel)
中定义。
但是,如果您将 Redis
用作应用程序的缓存驱动程序,则可能需要更改此映射以使用 Illuminate\Routing\Middleware\ThrottleRequestsWithRedis
类。
此类在使用 Redis
管理速率限制方面更为有效:
# 使用 Redis 限流
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
# 伪造表单方法
HTML 表单不支持 PUT
, PATCH
或 DELETE
请求。 所以,当定义 PUT
,PATCH
或 DELETE
路由用在 HTML 表单时,您将需要一个隐藏的加 _method
字段在表单中。 该 _method
字段的值将会与 HTTP 请求一起发送。
<form action="/example" method="POST">
<input type="hidden" name="_method" value="PUT">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
2
3
4
为了方便起见,您可以使用 @method
Blade 指令 生成 _method
字段:
<form action="/example" method="POST">
@method('PUT')
@csrf
</form>
2
3
4
# 路由模型绑定
# 隐式绑定
use App\Models\User;
Route::get('/users/{user}', function (User $user) {
return $user->email;
});
2
3
4
5
由于 $user
变量的类型暗示与 App\Models\user
Eloquent 模型一样,且变量名与 {user}
的 URI 片段相匹配,Laravel 会自动注入与请求 URI 中对应值 ID
匹配的模型实例。 如果在数据库中没有找到匹配的模型实例,则会自动生成一个 404 HTTP
响应。
# 定制缺失的模型行为
通常,如果没有找到隐式绑定模型,将生成 404 HTTP
响应。但是,你可以在定义路由时调用 missing
的方法来定制此行为。missing
的方法接受一个闭包,如果无法找到隐式绑定的模型,该闭包将被调用:
use App\Http\Controllers\LocationsController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
Route::get('/locations/{location:slug}', [LocationsController::class, 'show'])
->name('locations.view')
->missing(function (Request $request) {
return Redirect::route('locations.index');
});
2
3
4
5
6
7
8
9
# 跨域资源共享 (CORS)
Laravel 可以使用您配置 CORS
OPTIONS
的值自动响应 HTTP 请求。
可以在应用程序的 config/cors.php
配置文件中配置所有 CORS
设置。
这些 OPTIONS
请求将由默认情况下包含在全局中间件堆栈中的 HandleCors
中间件 自动处理。
您的全局中间件堆栈位于应用程序的 HTTP 内核 (App\Http\Kernel)
中。
# 路由缓存
# 生成路由缓存
php artisan route:cache
# 清除路由缓存
php artisan route:clear
2
3
4
5