前言:之前在学习并使用 Laravel 框架过程中,全是碎片化掌握,现在重新学习并记录一次学习的过程。
本文内容对应
Laravel8.*
版本。
直达入口:
一、介绍
本文内容根据 Laravel 官网路由模块学习。
Laravel
框架的所有默认路由文件都保存在routes
目录中。
- routes 目录
api.php
api 路由channels.php
验证配置文件console.php
广播事件配置文件web.php
定义 web 页面路由
1.1 基本路由
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::push($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
Route::match(['get', 'post'], '/', function(){
# 处理多种请求类型的路由
});
Route::any('/', function(){
# 处理所有请求类型的路由
});
1.2 重定向路由
Route::redirect('/here', '/there'); # 重定向路由
Route::redirect('/here', '/there', 301); # 重定向路由,默认返回状态码为 302
Route::permanentRedirect('/here', '/there'); # 重定向路由,默认使用 301 状态码返回
1.3 视图路由
# 第一个参数为 URI,第二个参数对应 resources/views 目录中的模板文件名
Route::view('/welcome', 'welcome');
1.4 控制器路由
use App\Http\Controllers\WelcomeController;
# 第一个参数为 URI,第二个参数对应控制器,会调用控制器 中的 show 方法
Route::get('/welcome', [WelcomeController::class, 'show']);
二、路由参数
2.1 必填参数
# 使用 {} 括起来的参数为必填参数, 参数名不能包含 - /
Route::get('goods_detail/{id}', $callback);
2.2 可选参数
# 使用 {参数名?} 格式的为可选参数,参数名不能包含 - /
Route::get('goods_detail/{id}/top/{is_top?}', $callback);
2.3 正则表达式约束
在路由定义上链式调用
where
方法中来约束路由参数的格式。
# 单个约束
Route::get('goods_detail/{id}', $callback)->where('id', '[0-9]+');
# 数组格式约束多个
Route::get('user_detail/{id}/{name}', $callback)->where(['id'=>'[0-9]+', 'name'=>'[a-z]+']);
# 字符过滤,Laravel 允许除 / 之外的所有字符,可使用正则表达式显式的允许成为占位符的一部分
Route::get('search/{string}', $callback)->where('string', '.*');
# 常用的辅助正则表达式模式
Route::get('user_detail/{id}/{name}', $callback)->whereNumber('id')->whereAlpha('name');
# whereAlpha()、whereAlphaNumeric()、whereNumber()、whereUuid()、assignExpressionToParameters($parameters, $expression)
2.4 全局约束
如果你希望某个参数在每个路由当中都遵循同一个正则表达式约束,则使用
Route::pattern()
方法在RouteServiceProvider
文件 的boot
方法中定义约束。
# app/Providers/RouteServiceProvider.php 文件
public function boot()
{
Route::pattern('id', '[0-9]+');
}
三、路由命名
在路由定义上链式调用
name
方法中为路由生成名称,路由名称是唯一的。
3.1 命名
# 闭包函数命名
Route::get('goods_detail/{id}', $callback)->name('goods_detail');
# 指定控制器行为命名
Route::get('goods_detail/', [GoodsController::class, 'show'])->name('goods_detail');
3.2 生成指定路由 URL
# 生成链接
$url = route('goods_detail');
# 生成带参数的链接
$url = route('goods_detail', ['id'=>1]);
# 生成重定向
return redirect()->route('goods_detail');
3.3 检查是否命中路由
如果你想判断当前请求是否指向某个命名过的路由,可链式调用
named
方法来判断。
if ($request->route()->named('goods_detail')){}
四、路由组
路由组允许在大量路由之间共享路由属性,例如中间件、子域名、前缀等。
4.1 中间件
Route::middleware(['first', 'second'])->group(function(){
Route::get('/', function(){
# 使用 first 和 second 中间件
});
Route::get('goods_detail/{id}', function(){
# 使用 first 和 second 中间件
});
});
4.2 子域名路由
# 应在注册根域名路由前注册子域名路由。
Route::domain('{account}.myapp.com')->group(function () {
Route::get('user/{id}', function ($account, $id) {
//
});
});
4.3 路由前缀
prefix()
方法将会为路由组中的每个路由的URI
添加前缀。
Route::prefix('admin')->group(function(){
Route::get('users', function(){
# 访问的URL是 /admin/users
});
});
4.4 路由名称前缀
链式调用
name
方法可为路由组中的每个路由添加指定的名称前缀。注意:确保前缀中包含.
字符。
Route::name('admin.')->group(function(){
Route::get('users', function(){
# 最终定义的路由名称是 admin.users
})->name('users');
});
五、路由与模型绑定
5.1 隐式绑定
在这个例子当中,
$user
类型提示为App\Models\User
Eloquent 模型,变量名$user
与 URI 中的{user}
相匹配,因此 Laravel 会自动注入与请求 URI 中传入的 ID 匹配的用户模型实例。
如果在数据库中未找到对应的模型实例,则自动生成 404 异常。
# 闭包路由写法
Route::get('api/users/{user}', function(App\Models\User $user){
return $user->email;
});
# 控制器写法
Route::get('users/{user}', [UserController::class, 'show']);
# 控制器代码
use App\Http\Controllers\UserController;
use App\Models\User;
public function show(User $user)
{
return view('user.profile', ['user' => $user]);
}
5.2 自定义匹配键名
默认使用
id
键名来解析 Eloquent 模型,可自定义键名。
use App\Models\Post;
use App\Models\User;
# 限定 $post 通过 slug 字段来检索
Route::get('api/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
return $post;
});
如果希望模型绑定在检索给定的模型类时,默认使用
id
以外的数据库字段,可重写Eloquent
模型上的getRouteKeyName
方法。
/**
* 获取该模型的路由的自定义键名
*
* @return string
*/
public function getRouteKeyName()
{
return 'slug';
}
5.3 显示绑定
要注册显示绑定,使用路由器的
model
方法,绑定参数指定的类。在app/Providers/RouteServiceProvider.php
文件类的boot
方法定义显示的绑定。
/**
* 定义你的路由模型绑定, pattern 过滤器等
*
* @return void
*/
public function boot()
{
Route::model('user', \App\Models\User::class);
// ...
}
绑定好后,就可以使用了。
# 上边已将 user 参数绑定给了 \App\Models\User 模型,所以 $user 会被注入该路由
Route::get('profile/{user}', function (App\Models\User $user) {
//
});
5.4 自定义解析逻辑
第一种: 在
app/Providers/RouteServiceProvider.php
文件类的boot
方法中使用Route::bind
方法自定义。
/** * 定义你的路由模型绑定, pattern 过滤器等 * * @return void */ public function boot() { Route::bind('user', function ($value) { return App\Models\User::where('name', $value)->firstOrFail(); }); // ... }
第二种:重写
Eloquent
模型上的resolveRouteBinding
方法。
/** * 检查绑定值的模型 * * @param mixed $value * @param string|null $field * @return \Illuminate\Database\Eloquent\Model|null */ public function resolveRouteBinding($value, $field = null) { return $this->where('name', $value)->firstOrFail(); }
六、回退路由
回退路由是指 没有命中其他路由的情况下才执行的路由。
注意:回退路由应始终是您应用程序注册的最后一个路由。
Route::fallback(function(){
#
});
七、限流
限注顾名思义就是限制流量的请求次数,在
app/Providers/RouteServiceProvider.php
文件中定义限流器。
使用
RateLimiter
门面的for
方法定义。for
方法接受「速率限制器名称」和「闭包返回限制配置」。
具体更多限制时段方法 查看 Illuminate\Cache\RateLimiting\Limit;
7.1 定义限流
# app/Providers/RouteServiceProvider.php 文件
# 1. 默认响应 429 状态码
RateLimiter::for('global', function (Request $request) {
return Limit::perMinute(1000);
});
# 2. 自定义响应内容,使用 response 方法
RateLimiter::for('global', function (Request $request) {
return Limit::perMinute(1000)->response(function () {
return response('Custom response...', 429);
});
});
# 3. 可用 $request 实例调取参数,VIP 无限制,不是 VIP 则按身份验证请求频率
RateLimiter::for('uploads', function (Request $request) {
return $request->user()->vipCustomer()
? Limit::none()
: Limit::perMinute(100);
});
# 4. 范围频率限制
RateLimiter::for('uploads', function (Request $request) {
return $request->user()->vipCustomer()
? Limit::none()
: Limit::perMinute(100)->by($request->ip());
});
# 5. 多个频率限制
RateLimiter::for('login', function (Request $request) {
return [
Limit::perMinute(500),
Limit::perMinute(3)->by($request->input('email')),
];
});
7.2 路由器分配限流
使用
throttle
关键字将配置好的频率限制器名称放到中间件middleware
数组中。
Route::middleware(['throttle:uploads'])->group(function () {
Route::post('/audio', function () {
//
});
Route::post('/video', function () {
//
});
});
八、表单方法伪造
Html 表单不支持
put
、patch
或delete
请求,但可以在form
表单中添加_method
隐藏域来实现以上请求。
<form action="/foo/bar" method="POST">
<input type="hidden" name="_method" value="PUT">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
// 或
<form action="/foo/bar" method="POST">
@method('PUT')
@csrf
</form>
九、访问当前路由
$route = Route::current();
$name = Route::currentRouteName();
$action = Route::currentRouteAction();