Laravel 路由
博客原文地址:https://www.ryanzoe.top/php/laravel/laravel-route/
版本:Laravel 7.13.0
Laravel 中的路由是什么?
对任何一个 Web 应用框架而言,通过 HTTP 协议处理用户请求并返回响应都是核心必备功能,也就是说,对于我们学习和使用一个 Web 框架,第一件要做的事情就是定义应用路由,否则,将无法与终端用户进行交互。
Laravel 路由可以定位到程序具体使用哪个 PHP 文件或者控制器,Laravel是一个强路由的框架,所有的请求都必须先定义好路由才能访问。
应用中的大多数路由都会定义在 routes/web.php 文件中。最简单的 Laravel 路由由URI 和闭包回调函数组成。
路由配置文件
所有的 Laravel 路由都在 routes
目录中的路由文件中定义,这些文件都由框架自动加载。
routes/web.php
用于定义 web 界面的路由,这里面的路由都会被分配给 web 中间件组,它提供了会话状态和 CSRF 保护等功能。
定义路由最简单的方式就是在 routes/web.php
中定义一个 URI 和一个映射到该路径的闭包函数:
// routes/web.php Route::get('/', function () { return 'Hello, World!'; });
这样,当我们访问应用首页 http://localhost/
时,就可以看到页面显示 Hello, World!
这一行字符串。这就是一个最简单的 Laravel 路由定义。
这里需要注意的是,我们并没有通过 echo
或 print
显示输出内容,而是通过 return
将其返回,Laravel 会通过内置的响应机制和中间件对返回内容进行处理。
很多简单的静态 Web 站点通过这种最基本的路由定义就可以完成了,比如一些企事业单位宣传网站,只有一些静态页面,通过几个 GET 路由以及视图模板就可以搞定了,如下所示,使用 Laravel 开发静态站点,就是这么简单!
// routes/web.php // 首页 Route::get('/', function () { return view('welcome'); }); // 关于我们 Route::get('about', function () { return view('about'); }); // 产品页 Route::get('products', function () { return view('products'); }); // 服务页 Route::get('services', function () { return view('services'); });
routes/api.php
处理其他接入方的 API 请求(通常是跨语言、跨应用的请求),定义在 routes/api.php 中的路由都是无状态的,并且被分配了 api 中间件组。在这个路由组中,会自动添加 URL 前缀/api
到此文件中的每个路由,这样你就无需再手动添加了。你可以在RouteServiceProvider
类中修改此前缀以及其他路由组选项。
// routes/api.php Route::get('/test', function () { return view('welcome'); });
在 api.php 中定义了路由后,会自动加上 “api“ 前缀,可以通过下面的 url 访问到 welcome 视图的内容
http://localhost/api/test
^^^
如果想要修改默认的 “api“ 前缀,可以到 app/Providers/RouteServiceProvider.php 中修改,例如下面的代码将默认的 “api“ 前缀修改为 “ryan”
protected function mapApiRoutes() { Route::prefix('ryan') ->middleware('api') ->namespace($this->namespace) ->group(base_path('routes/api.php')); }
routes/console.php
定义了基于控制台的应用入口(和路由作用一样),也就是定义 artisan 闭包命令
在routes/console.php 文件中,可以看到默认定义了一个 inspire 命令,运行后会显示乔布斯说过的一句名言。
> php artisan inspire The only way to do great work is to love what you do. - Steve Jobs
我们可以使用 Artisan::command 方法定义基于闭包的自定义命令路由。
// routes/console.php Artisan::command('test {project}', function ($project) { $this->info("Testing {$project}!"); })->describe('test a project');
说明:
command 方法接收两个参数 —— 命令标识和接收命令参数和选项的闭包
命令行中调用
> php artisan test demo
Testing demo!
查看命令详情
> php artisan --help test Description: test a project Usage: test <project> Arguments: project
routes/channels.php
定义广播频道的授权规则
// routes/channels.php Broadcast::channel('order.{orderId}', function ($user, $orderId) { return $user->id === Order::findOrNew($orderId)->user_id; });
channel
方法接收两个参数:频道名称和一个回调函数,该回调通过返回 true
或者 false
来表示用户是否被授权监听该频道。
路由基础配置
路由方法
上面的路由定义中使用了 Route::get
,这种语法的含义是只匹配 GET 请求路由,那如果提交的是 POST 请求,或者 PUT、DELETE 请求呢?Laravel 框架也为我们提供了能响应任何 HTTP 请求的路由:
Route::post('/', function () {}); Route::put('/', function () {}); Route::delete('/', function () {}); Route::patch('/', function () {}); Route::options('/', function () {});
此外,还可以通过 Route::any
定义一个可以捕获任何请求方式的路由:
Route::any('/', function () {});
从安全角度说,并不推荐上述这种捕获如何请求方式的路由定义方式,但是兼顾到便利性,我们可以通过 Route::match
指定请求方式白名单数组,比如下面这个路由可以匹配 GET 或 POST 请求:
Route::match(['get', 'post'], '/', function () {});
仅支持 HTTPS 的路由:
Route::get('/', array('https', function () {}));
复杂业务逻辑处理
传递闭包并不是定义路由的唯一方式,闭包简单快捷,但是随着应用体量的增长,将日趋复杂的业务逻辑全部放到路由文件中显然是不合适的,另外,通过闭包定义路由也无法使用路由缓存从而优化应用性能。对于稍微复杂一些的业务逻辑,我们可以将其拆分到控制器方法中实现,然后在定义路由的时候使用控制器+方法名来取代闭包函数:
Route::get('/', 'WelcomeController@index');
这段代码的含义是将针对 /
路由的 GET 请求传递给 App\Http\Controllers\WelcomeController
控制器的 index
方法进行处理。你可以将之前定义的闭包函数内的代码移植到 index
方法中,效果完全一样
路由参数
如果你定义的路由需要传递参数,只需要在路由路径中进行标识并将其传递到闭包函数即可:
Route::get('user/{id}', function ($id) { return "用户ID: " . $id; });
当你访问 http://localhost/user/1000
的时候,就可以在浏览器看到 用户ID: 1000
字符串。
此外,还可以定义可选的路由参数,只需要在参数后面加个 ?
标识符即可,同时你还可以为可选参数指定默认值:
Route::get('user/{id?}', function ($id = 1) { return "用户ID: " . $id; });
更高级的,你还可以为路由参数指定正则匹配规则:
Route::get('page/{id}', function ($id) { return '页面ID: ' . $id; })->where('id', '[0-9]+'); Route::get('page/{name}', function ($name) { return '页面名称: ' . $name; })->where('name', '[A-Za-z]+'); Route::get('page/{id}/{slug}', function ($id, $slug) { return $id . ':' . $slug; })->where(['id' => '[0-9]+', 'slug' => '[A-Za-z]+']);
如果传入的路由参数与指定正则不匹配,则会返回 404 页面
重定向路由
如果要定义重定向到另一个 URI 的路由,可以使用 Route::redirect
方法。这个方法可以快速的实现重定向,而不再需要去定义完整的路由或者控制器:
Route::redirect('/here', '/there');
Route::redirect
默认会返回状态码 302
。 你可以通过第三个参数自定义返回码:
Route::redirect('/here', '/there', 301); // 也可以使用 Route::permanentRedirect 方法来返回 301 状态码 Route::permanentRedirect('/here', '/there');
路由命名
在应用其他地方引用路由的最简单的方式就是通过定义路由的第一个路径参数,你可以在视图中通过辅助函数 url()
来引用指定路由,该函数会为传入路径加上完整的域名前缀,所以 url('/')
对应的输出是 http://localhost
。你可以在视图文件中这么使用:
<a href="{{ url('/') }}">
此外,Laravel 还允许你为每个路由命名,这样一来,不必显式引用路径 URL 就可以对路由进行引用,这样做的好处是你可以为一些复杂的路由路径定义一个简单的路由名称从而简化对路由的引用,另一个更大的好处是即使你调整了路由路径(在复杂应用中可能很常见),只要路由名称不变,那么就无需修改前端视图代码,提高了系统的可维护性。
路由命名很简单,只需在原来路由定义的基础上以方法链的形式新增一个 name
方法调用即可:
Route::get('user/{id?}', function ($id = 1) { return "用户ID: " . $id; })->name('user.profile');
前端视图模板中可以通过辅助函数 route
并传入路由名称(如果有路由参数,则以数组方式作为第二个参数传入)来引用该路由:
<a href="{{ route('user.profile', ['id' => 100]) }}"> // 输出:http://localhost/user/100
如果没有路由参数,通过 route('user.profile')
引用即可。此外,我们还可以简化对路由参数的传递,比如上例可以简化为:
<a href="{{ route('user.profile', [100]) }}">
查看定义好的路由
> php artisan route:list
在实际开发过程中,推荐使用路由命名来引用路由。