1.1 路由定义
路由的基本两个作用:1. 美化url 2.隐藏路径使之更加安全,几乎所有的框架无论前后台框架,vue.js、node.js、tp、laravel 中都会单独给路由划分一个模块,它的核心作用其实就只有一件事,分发请求。根据url的路径去判断和处理,返回不同的处理结果给用户,路由文件都存放在 routes 目录下:这些文件都由框架自动加载。如下图
1.2 基本路由
构建基本路由只需要一个 URI 与一个 闭包. 下面展示了 laravel 下入口文件 public/index.php
下使用的路由。 这才是实际上的首页面 resources\views\welcome.blade.php
,它是一个视图路由。
<?php
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Laravel中提供了这些常见的方法去使用路由
<?php
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
1.3 自定义路由
1.3.1 创建路由文件
在 Routes/web.php
文件下先模仿它创建一个文件 my.php
,在其中构建一个最基本的路由。注意这里的路由是区分大小写的
<?php
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Route;
/**
* 1. 路由基本
*/
// 构建一个基本路由
Route::get('say', function () {
return 'Say Hi';
});
1.3.2 注册路由
去这里注册自己的路由 app/Providers/RouteServiceProvider.php
,简单来说就是去路由服务提供者类中去注册路由,去掉多余的部分,我们模仿其他注册的路由,添加一个方法 protected function mapMyRoutes()
,并且去 map()
方法中完成映射
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
/**
* 路由服务提供类,继承于服务提供类
*/
class RouteServiceProvider extends ServiceProvider
{
... ...
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
$this->mapMyRoutes();
}
protected function mapMyRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/my.php'));
}
... ...
}
1.3.2 使用
直接 postman 测试,OK。
1.4 CSRF 保护
继续在my.php 中添加路由规则,我们发现并不可行。这是因为CSRF的保护机制
my.php
中添加的内容
<?php
Route::post('lxm', function () {
return 'for to lxm';
});
1.4.1 放行白名单
第一种方式:添加放行白名单,位置 app/Http/Middleware/VerifyCsrfToken.php
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
protected $except = [
'lxm', // 加在了这里
];
}
1.4.2 取消这个中间件CSRF验证
第二种使用方式:取消这个中间件 app/Http/Kernel.php
下注释这个验证 CSRF (但是,我们一般不这样做,当然也不推荐这么做)
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
// \App\Http\Middleware\VerifyCsrfToken::class, // 就是这里
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
}
同样OK
1.5 路由匹配的请求
http 的请求有很多种,我们知道远远不止 get、post,这里有两种方式对这些请求进行处理。
1.5.1 match
匹配多种请求方式,用一个数组来挂载我们需要的请求。
/**
* match 匹配多种访问方式
*/
Route::match(['get', 'post', 'put'], 'link', function () {
return 'for to link';
});
1.5.2 any
几乎大多数的请求都可以。
/**
* any 几乎可以匹配所有的访问方式
*/
Route::any('park', function () {
return 'for to park';
});
1.6 路由参数
- 使用get请求传递参数,同样的像其他框架一样为了保持url的美丽
- a. 使用/隔开参数
- b. 必须有{},其中包含我们的参数
- c. 这个参数可以是单个也可以是多个,后面的那个回调函数进行形参的传递,顺序对应了就好了
1.6.1 单个参数
<?php
/**
* 单个参数
*/
Route::get('user1/{id}', function ($id) {
return '传递的用户ID:' . $id;
});
1.6.2 多个参数
<?php
Route::get('user2/{id}/{name}/{age}', function ($p1, $p2, $p3) {
return 'id:' . $p1 . ',' . 'name:' . $p2 . ',' . 'age:' . $p3;
});
1.6.3 可选参数
- 必选参数和可选参数
- 可选:同样的也可以使用可选参数{id?},标记一个?来标记这是一个可选按参数 只是,我每标记一个可选参数,就必定需要在后面得到回调闭包中给定一个默认值 ,一般我们将可选的放在最后,防止匹配出错
- 必选:像是上面那种使用方式,就是必选参数,规定必须将参数传递过来
<?php
// 我测试一下,不传递age
Route::get('user3/{id}/{name}/{age?}', function ($id, $name, $age = 24) {
return 'id:' . $id . ',' . 'name:' . $name . ',' . 'age:' . $age;
});
1.7 使用正则约束
1.7.1 正则约束
- a. 可以单个约束
- b. 可以多个约束
- c. where链式结构的操作觉得麻烦的话使用数组的方法,因为PHP中数组这个强大的数据结构,是关联数组十分好用 …..
<?php
Route::get('user4/{name}', function ($name) {
//
})->where('name', '[A-Za-z]+');
Route::get('user4/{id}', function ($id) {
//
})->where('id', '[0-9]+');
Route::get('user4/{id}/{name}', function ($id, $name) {
//
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
1.7.2 全局约束
如果你希望某个具体的路由参数都遵循同一个正则表达式的约束,就使用 pattern 方法在
app\Providers\RouteServiceProvider.php
的 boot 方法中定义这些模式:
<?php
/**
* Define your route model bindings, pattern filters, etc.
* 全局限定, 可以在这里限制, 这个限制是所有路由生效之前的限制
* @return void
*/
public function boot()
{
//
// Route::pattern('id', '[0-9]+'); // 加在了这里
parent::boot();
}
1.8 路由组中的使用
1.8.1 路由命名
- 路由命名,为路由重定向服务。如下面的操作, 我觉得有时候访问 a/b/c/d 这个也太长了,但是我也需要保留这个路由,这个时候我们就可以通过给这个路由一个name,其实相当于一个别名,然后我们通过其他的路由,重定向到这个路由,这个name必不可少
<?php
Route::get('a/b/c/d', function () {
return 'in aaa';
})->name('d');
Route::get('e', function () {
return redirect()->route('d');
});
1.8.3 路由前缀
给一组路由统一规范,如下面的代码。
<?php
/**
* 路由前缀
*/
Route::prefix('admin')->group(function () {
Route::get('addUser', function () {
return 'addUser';
});
Route::get('editUser', function () {
return 'editUser';
});
Route::get('delUser', function () {
return 'delUser';
});
Route::get('updateUser', function () {
return 'updateUser';
});
});
1.8.3 路由名称前缀
<?php
/**
* 路由名称前缀
*/
Route::name('admin.')->group(function () {
Route::get('addUser', function () {
return '添加用户';
})->name('add');
Route::get('delUser', function () {
return '删除用户';
})->name('del');
Route::get('editUser', function () {
return '修改用户';
})->name('edit');
Route::get('selUser', function () {
return '查询用户';
})->name('sel');
});
/**
* 下面重定向一下
*/
Route::get('1', function () {
return redirect()->route('admin.add');
});
Route::get('2', function () {
return redirect()->route('admin.del');
});
Route::get('3', function () {
return redirect()->route('admin.edit');
});
Route::get('4', function () {
return redirect()->route('admin.sel');
});
下面我通过访问 1、2、3、4,来进而处理页面的CURD请求
1
2
3
4
1.8.4 domain 访问控制
如下,我进行域名限制,要求只能够通过 blog.com 下的域名才是有效的请求路径
<?php
/**
* 子域名路由
*/
Route::domain('blog.com')->group(function () {
Route::get('user/{id}', function ($id) {
return "访问ID是 $id";
});
});
正常访问
1.8.5 路由组链式调用及数组
<?php
/**
* 链式调用和数组
*/
Route::prefix('larave')->name('admin')->group(function(){
Route::get('lyym',function(){
return '检测路由域名';
});
});
Route::group(['prefix'=>'admin','domain'=>'blog.com'],function(){
Route::get('lyhh',function(){
return '数组方式';
});
});
1.9 路由中间件
1.9.1 创建中间件
- 项目根目录下运行:
php artisan make:middleware 中间件名称
如下图创建了一个叫做Test的中间件
1.9.2 编写中间件
打开干刚刚创建的Test中间件,加入line18这行代码
<?php
namespace App\Http\Middleware;
use Closure;
class Test
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
echo "我是中间件 Test \r";
return $next($request);
}
}
1.9.3 注册中间件
blog\app\Http\Kernel.php
的$routeMiddleware
中注册对应的中间件,注意写上自定义中间件的命名空间,要不会找不到的。
<?php
namespace App\Http;
use App\Http\Middleware\Test; // 注意这里也要写,否则找不到
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
// 'test' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'test' => Test::class, // 写这里了
];
}
1.9.4 使用中间件
<?php
# 使用
Route::middleware('test')->group(function(){
Route::get('ly',function(){
return '检测路由中间件';
});
});
OK