当前位置: 首页 > 后端技术 > PHP

Laravel路由学习笔记

时间:2023-03-29 14:02:35 PHP

routing本文主要讲解Laravel框架中路由的基础知识,主要参考中文文档中的路由章节,结合自己的理解。通俗易懂的剖析Laravel框架中最重要的路由知识。一、必备知识在学习Laravel路由之前,我们应该对以下知识有一个很好的了解。第一个是HTTP协议的基础知识。不需要完全理解HTTP协议,但需要了解一小部分概念。如果你不理解,你在阅读laravel文档时会产生很多困惑。对HTTP协议的理解,可以参考这篇深入理解HTTP协议的文章。第二个是——RESTful,这是一种设计思想,对学习laravel路由很有帮助,尤其是在学习laravelcontroller的资源控制器部分。很多人的疑惑是因为不了解RESTful在这种情况下产生的。在阮一峰的日记中,有两篇文章详细讲解了RESTful,其中一篇是理解RESTful架构。2.路由学习①路由定义文件Laravel所有的路由都定义在routes目录下的路由文件中,这些文件由框架自动加载。routes/web.php文件用于定义Web界面的路由。这里面的路由会被分配到web中间件组,提供会话状态和CSRF保护等功能。routes/api.php中定义的路由是无状态的,并分配给api中间件组。大多数应用程序构建都是从在routes/web.php文件中定义路由开始的。可以通过在浏览器中输入定义的路由URL来访问routes/web.php中定义的路由。例如,您可以在浏览器中输入http://your-app.dev/user来访问以下路由Route::get('/user','UserController@index');②基本路由构建基本路由只需要一个URI和一个闭包函数(什么是闭包函数,如果想深入了解闭包函数,请看这个PHP闭包),这里提供一种非常简单优雅的路由定义方式:Route::get('foo',function(){return'HelloWorld';});③可用的路由方法路由器允许您注册一条可以响应任何HTTP请求的路由。大致有以下七种Route::get('books','BooksController@index');//获取路由::post('books','BookController@store');//保存Route::get('books/create','BookController@create');//创建路由::get('books/:id','BookController@show');//显示路由::put('books/:id','BookController@update');//更新路由::delete('books/:id','BookController@destroy');//删除Route::get('books/:id/edit','BookController@edit');//编辑以上七个方法可以使用Route:source方法进行总结使用。Route:source方法后面会详细解释。Route::resource('books','BooksController');有时您可能需要注册一个可以响应多个HTTP请求的路由。这时候可以使用match方法,也可以使用any方法注册一个响应所有HTTP请求的实现Request路由,但是根据面向对象的单一职责原则,一个类或者一个模块应该有一个而且只有一种责任,所以不推荐。(什么是单一职责原则?请看这篇文章单一职责原则)Route::match(['get','post'],'/',function(){//});Route::any('foo',功能(){//});④重定向路由如果要定义重定向到另一个URI的路由,可以使用Route::redirect方法。该方法无需定义完整的路由或控制器即可快速实现重定向:Route::redirect('/here','/there');Route::redirect默认返回状态码302。可以通过第三个参数自定义返回码:Route::redirect('/here','/there',301);您还可以使用Route::permanentRedirect方法返回301状态代码:Route::permanentRedirect('/here','/there');⑤查看路由如果你的路由只需要返回一个视图,可以使用Route::view方法。它和重定向一样方便,不需要定义完整的路由或控制器。view方法有三个参数,第一个是必需的,是一个包含视图名称的URI。第二个也是必需的参数是需要呈现的视图的名称。第三个参数为可选参数,可以传入一个数组,数组中的数据会传递给视图:Route::view('/welcome','welcome');//参数一:URL参数二:视图名称Route::view('/welcome','welcome',['name'=>'Taylor']);//参数1:URL参数2:视图名称参数3:可选参数(可传数组)⑥路由参数1>必选参数当然,有时需要抓取路由中的一些URL片段。例如,要从URL中捕获用户ID,您可以通过定义路由参数来实现:Route::get('user/{id}',function($id){return'User'.$id;});你也可以根据需要在路由中定义多个参数:Route::get('posts/{post}/comments/{comment}',function($postId,$commentId){//});路由的参数通常放在{}里面,参数名只能是字母,路由参数不能包含-符号,必要时可以用下划线(_)代替。路由参数将依次注入路由回调或控制器,而不管回调或控制器的参数名称。2>可选参数有时候,你可能需要指定一个路由参数,但又希望这个参数是可选的。你可以加一个?标记在参数后面来实现这个,但前提是你确保路由的相应变量具有默认值Route::get('user/{name?}',function($name=null){return$name;});Route::get('user/{name?}',function($name='John'){return$name;});3>正则表达式约束可以使用where方法约束路由实例的路由参数格式。where方法接受一个参数名称和一个定义参数应如何约束的正则表达式: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]+','名称'=>'[a-z]+']);4>全局约束如果你想让一个特定的路由参数遵循同一个正则表达式的约束,使用pattern方法在appProvidersRouteServiceProvider的boot方法中定义这些模式:/***定义你的路由模型绑定,模式过滤器等.**@returnvoid*/publicfunctionboot(){Route::pattern('id','[0-9]+');parent::boot();}一旦定义,这些规则将自动应用于所有使用此参数名称的路由:Route::get('user/{id}',function($id){//仅在以下情况下执行id是一个数字。});⑦路由命名路由命名可以方便地为特定路由生成URL或重定向。您可以通过在路由定义上链接name方法来指定路由名称:Route::get('user/profile',function(){//})->name('profile');也可以指定控制器行为路由名称:Route::get('user/profile','UserProfileController@show')->name('profile');生成指定路由的URL指定路由名称后,可以使用全局辅助函数route生成链接或重定向到该路由://GenerateURL...$url=route('profile');//生成重定向...returnredirect()->route('profile');如果有定义带参数的命名路由,可以将参数作为路由函数的第二个参数传入,指定的参数会自动插入到URL中的相应位置:Route::get('user/{id}/profile',function($id){//})->name('profile');$url=route('profile',['id'=>1]);如果要判断当前请求是否指向某个路由,可以通过调用路由实例上的命名方法来检查当前路由。例如,你可以在路由中间件中查看当前的路由名称:/***处理一个请求。**@param\Illuminate\Http\Request$request*@param\Closure$next*@returnmixed*/publicfunctionhandle($request,Closure$next){if($request->route()->named('profile')){//}return$next($request);}⑧路由组路由组允许您在大量路由之间共享路由属性,例如中间件或命名空间,而无需为每个路由单独定义它们路由这些属性。共享属性应在Route::group方法的第一个参数中作为数组传递。1>路由组中的共享中间件要将中间件分配给路由组中的所有路由,可以在组前调用中间件方法,中间件将按照它们在数组中列出的顺序运行。Route::middleware(['first','second'])->group(function(){Route::get('/',function(){////使用第一个和第二个中间件});Route::get('user/profile',function(){////使用第一个和第二个中间件});});2>路由组中共享命名空间的另一个常见用例是使用命名空间方法将相同的PHP命名空间分配给路由组中的所有控制器。Route::namespace('Admin')->group(function(){//"App\Http\Controllers\Admin"命名空间中的控制器});请记住,默认情况下,RouteServiceProvider将被命名为命名空间组,允许您注册控制器路由而无需指定完整的AppHttpControllers命名空间前缀。因此,您只需指定命名空间AppHttpControllers之后的部分。3>路由组中的共享子域路由组也可以用来处理子域。可以为子域分配路由参数,如路由URI,允许您获取子域的一部分作为路由或控制器的参数。可以在组之前调用域方法来指定子域。(什么是子域名)Route::domain('{account}.myapp.com')->group(function(){Route::get('user/{id}',function($account,$id){//});});3>路由组中的共享路由前缀可以使用prefix方法为路由组中给定的URL添加前缀。例如,您可以为组中所有路由的URI加上admin前缀。Route::prefix('admin')->group(function(){Route::get('users',function(){//匹配包含"/admin/users"的URL});});4>路由组中的共享路由名前缀名方法可用于为路由组中的每个路由名添加给定的字符串。例如,您可能希望在所有组路由的名称前加上“admin”。给定的字符串与指定的路由名称前缀完全相同,因此我们将确保提供结尾的.characterintheprefix.Route::name('admin.')->group(function(){Route::get('users',function(){//指定路由名称为“admin.users”...})->name('users');});⑨路由模型绑定在路由或控制器行为ID中注入模型时,需要查询ID对应的模型。Laravel提供了一种路由模型绑定的方法,可以自动将模型实例直接注入到路由中。例如,您可以注入与给定ID匹配的整个用户模型实例,而不是注入用户的ID。1>隐式绑定Laravel将自动解析Eloquent模型,这些模型定义的路由段名称与路由或控制器操作中的类型提示变量名称匹配。例如:Route::get('api/users/{user}',function(App\User$user){return$user->email;});在这个例子中,由于$user变量被类型提示为Eloquent模型AppUser,并且变量名与URI中的{user}匹配,所以Laravel会自动注入与请求中传入的ID相匹配的User模型实例网址。如果在数据库中找不到对应的模型实例,会自动产生404异常。2>自定义键名如果希望模型绑定在检索给定模型类时使用id以外的数据库字段,可以重写Eloquent模型上的getRouteKeyName方法:/***获取模型的路由自定义键名.**@returnstring*/publicfunctiongetRouteKeyName(){return'slug';}2>显式绑定要注册显式绑定,请使用路由器的模型方法为给定参数指定类。在RouteServiceProvider类的引导方法中定义这些显式模型绑定。公共功能启动(){父级::启动();Route::model('user',App\User::class);}接下来,定义一个包含{user}参数的路由:Route::get('profile/{user}',function(App\User$user){//});由于我们已将所有{user}参数绑定到AppUser模型,因此User实例将被注入到此路由中。例如,对profile/1的请求将在数据库中注入ID为1的User实例。如果在数据库中找不到匹配的模型实例,则会自动抛出404异常。2>自定义逻辑解析如果要使用自定义解析逻辑,使用Route::bind方法。传递给bind方法的Closure将接受URI中花括号对应的值,并返回你要在这个路由中注入的类的实例:/***启动应用程序服务。**@returnvoid*/publicfunctionboot(){parent::boot();Route::bind('user',function($value){returnApp\User::where('name',$value)->first()??abort(404);});}或者,你可以覆盖Eloquent模型上的resolveRouteBinding方法。此方法将接受与URI中花括号对应的值,并返回要在此路由中注入的类的实例。/***检索绑定值的模型。**@parammixed$value*@return\Illuminate\Database\Eloquent\Model|null*/publicfunctionresolveRouteBinding($value){返回$this->where('name',$value)->first()??abort(404);}2>Fallbackrouting使用Route::fallback方法,您可以定义一个路由,当没有其他路由匹配传入请求时,该路由将被执行。通常,未处理的请求会通过应用程序的异常处理程序自动呈现“404”页面。但是,由于您可以在routes/web.php文件中定义回退路由,因此来自web中间件的所有中间件都将应用于该路由。当然,你也可以根据需要给这个路由添加额外的中间件:Route::fallback(function(){//});注意:后备路由应始终是您的应用程序注册的最后一条路由。⑩访问控制Laravel包含一个中间件,用于控制应用程序对路由的访问。如果要使用它,请将节流中间件分配给路由或路由组。throttle中间件采用两个参数来确定在给定分钟数内可以发出的最大请求数。例如,我们指定一个经过身份验证且用户访问频率不超过每分钟60次的路由组。Route::middleware('auth:api','throttle:60,1')->group(function(){Route::get('/user',function(){//});});1>动态访问控制您可以根据经过身份验证的用户模型的属性指定动态请求的最大值。例如,如果您的User模型包含一个rate_limit属性,您可以将属性名称传递给throttle中间件,以便它可以用于计算最大请求数:Route::middleware('auth:api','throttle:rate_limit,1')->group(function(){Route::get('/user',function(){//});});?Form方法假HTML表单不支持PUT、PATCH或DELETE行为。因此,当您想要从HTML表单调用定义PUT、PATCH或DELETE行为的路由时,您需要向表单添加一个隐藏的_method输入标签。使用_method字段的值作为HTTP请求方法:您还可以使用@method模板指令生成_method输入:@method('PUT')@csrfCSRF保护任何指向在网络路由文件中定义的POST、PUT或DELETE路由的HTML表单都应包含CSRF令牌字段,否则,请求将被拒绝。您可以在CSRF文档中阅读有关CSRF的更多信息。@csrf...?要访问当前路由,您可以使用Routefacade上的current、currentRouteName和currentRouteAction方法来访问有关路由的信息处理传入的请求。$route=Route::current();$name=Route::currentRouteName();$action=Route::currentRouteAction();