ルーティングは、相互接続されたネットワークを通じて送信元アドレスから宛先アドレスに情報を送信するアクティビティです。ルーティングは、OSI ネットワーク参照モデルの 3 番目の層であるネットワーク層で行われます。
通常、すべてのルートは app/Http/routes.php ファイルで定義され、その内容はフレームワークによって自動的にロードされます。リソース表現アドレスと Closure クロージャ関数を渡すだけで定義できます。
Route::get('foo', function () { return 'Hello world!'; });
routes.php ルーティング ファイルは appProvidersRouteServiceProvider.php にロードされ、ロード中に Web ミドルウェア グループが使用されます (バージョン>=5.2)。このミドルウェア グループはappHttpkernel.php の $middlewareGroups 変数で定義されているこのミドルウェア グループは、Cookie 暗号化、Cookie 応答、セッションの有効化、ビューへのエラー セッションの自動挿入、および csrf 保護の機能を提供します。アプリケーションのルートのほとんどは、このルート ファイルで定義する必要があります。
ルーティングでは、ルートの登録時に任意の http リクエスト メソッドを使用できます。
Route::get($uri, $callback);Route::post($uri, $callback);Route::put($uri, $callback);Route::patch($uri, $callback);Route::delete($uri, $callback);Route::options($uri, $callback);
ルートの登録時に複数のメソッドを許可する必要がある場合があります。リクエスト メソッド。このとき、メソッド メソッドを使用する必要がある場合があります。もちろん、any メソッドを使用して、パラメータ付きの
Route::match(['get', 'post'], function () { // });Route::any('foo', function () { //})
複数のルート パラメータを取得するには、次のようにします。
Route::get('user/{id}', function ($id) { return 'user_id is: ' . $id;});
ルーティング パラメータは {} で定義され、ルートにアクセスするたびに、関連する登録済みパラメータが順番にクロージャ関数に渡されます。 . ri.
Route::get('posts/{post}/comments/{comment}', function ($post, $comment) { // });
ps: ルーティング パラメータには **-** を含めることはできず、**_** に置き換える必要があります (例: {user_id}
オプションのパラメータ routing
<🎜) >パラメータを使用してルートを定義する必要がある場合がありますが、そうでない場合は、{name?} を使用してオプションのルートを定義する必要があります。正規表現を使用してパラメータを制約します。
Route::get('user/{name?}', function ($name = null) { return $name; });Route::get('user/{name?}', function ($name = 'john'){ return $name; });
一致するすべてのルート パラメーターが同じ制約を受けるように、グローバル制約式を定義できます。この時点では、ルートを開始する前に制約を登録する必要があります。ルートを開始する前に、ルーティング サービス プロバイダー ファイルに制約を追加する必要があります。ファイルは appProvidersRouteServiceProvider.php
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-zA-Z]+');
public function boot(Router $router) { $router->pattern('id', '[0-9]+'); parent::boot($router);}
名前付きルート
$router->pattern('id','[0-9]+');Route::get('user/{id}', function ($id) { // });
名前付きルートは、リソース表現アドレスを簡単に生成し、指定されたルーティング アドレスにルートをリダイレクトできます。ルートを登録するときに 2 番目のパラメーターを配列パラメーターとして渡し、インデックスとして追加できます:
Route::get('user/profile', ['as' => 'profile', function () { //}]);
Route::get('user/profile', ['as' => 'profile', 'use' => 'UserController@showProfile']);
ルーティンググループを使用する場合、グループ名プレフィックスをグループ全体に追加することもできます。もちろん、laravel はこれをサポートしています:
Route::get('user/profile', 'UserController@showProfile')->name('profile');
ルートに名前を付けたら、グローバル ヘルパー関数のルートを使用してルート URL アドレスを生成できます。これは、リダイレクト時のリダイレクト アドレスの生成にも使用できます。
Route::group(['as' => 'admin::'], function () { Route::get('dashboard', ['as' => 'dashboard', function () { // route named 'admin::dashboard' // you can redirect to this use route('admin::dashboard') }]) ;});
// Generating URLs...$url = route('profile');// Generating Redirects...return redirect()->route('profile');
ルーティング グループの使用ミドルウェアや名前空間の共有など、一部のルーティング機能の共有が容易になり、各ルートで同じミドルウェアや名前空間を個別に定義する必要がなくなります。ルート グループは Route::group を使用して定義され、最初のパラメータで機能を共有します。このパラメータは配列です。共有ミドルウェアを作成するには、ミドルウェア インデックスを使用します。このように、ルーティング グループで定義されたルートは、一致するときにミドルウェアを導入します。
Route::get('user/{id}/profile', ['as' => 'profile', function ($id) { // }]);$url = route('profile', ['id' => 1]);
ルーティング グループのもう 1 つの一般的な例は、コントローラーで名前空間を共有することです。名前空間インデックスが使用される時間:
Route::group(['namespace' => 'Admin'], function () { // Controllers Within The 'App\Http\Controllers\Admin' Namespace Route::group(['namespace' => 'User'], function () { // Controllers Within The 'App\Http\Controllers\Admin\User' Namespace });});
因为我们大部分路由都是定义在routes.php文件里,而路由服务在提供服务时将该文件引入到路由组中,并共享了App\Http\Controllers命名空间,这样,在该文件中定义的控制器路由,可以不使用App\Http\Controllers前缀.
// Already Within The 'App\Http\Controllers' NamespaceRoute::get('user/profile', 'UserController@showProfile');
子域名路由可以做域名匹配路由,也就是说可以约束域名做匹配,如果不是匹配到的域名则不会注册该组内路由, 当然你可以对子域名进行类参数路由的约束,这样允许你捕获域名的一部分或全部:
Route::group(['domain' => '{account}.myapp.com'], function () { Route::get('user/{id}', function ($account, $id) { // });});
使用prefix索引可以在路由组中定义路由前缀,这样在该组内的路由都会自动使用该前缀:
Route::group(['prefix' => 'admin'], function () { Route::get('dashboard', function () { // Matches The 'admin/dashboard' URL });});
当然你可以在路由前缀中使用参数:
Route::group(['prefix' => 'accounts/{account_id}'], function () { Route::get('detail', function ($account_id) { // Matchs The '/accounts/{account_id}/detail' URL });});
跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并执行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去执行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
laravel框架自带csrf攻击保护措施,它被以中间件的形式引入到web路由组中,所以每个在routes.php文件中定义的路由被访问时都会经过csrf中间件的验证。你可以查看vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php文件,阅读其实现。csrf(跨站请求伪造)是一种恶意的攻击行为,它可以绕过用户的授权去执行未授权的行为。
laravel会为每个活跃用户生成一个csrf token,而这个token就是用来验证请求是不是真实用户授权的。所以你应该在每个表单中都使用隐藏的input并录入csrf token,这样提交表单的请求才能通过csrf中间件的验证.laravel提供了方便的形式去在表单中生成csrf token:
// Vanilla PHP<?php echo csrf_field(); ?>// Blade Template Syntax{{ csrf_field() }}
csrf_field()方法会生成以下html节点:
<input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
你并不需要去手动的验证这些能够修改状态的http请求,比如 post, put, delete, 因为VerifyCsrfToken中间件已经自动处理这些请求了,它会自动的根据请求中的token与会话中存储的token进行匹配验证。
有时候我们可能需要排除个别url,让他不受csrf的保护,因为可能我们需要挂接一些其他的第三方系统,这个时候系统之间的通讯是不应该使用csrf机制去验证的,比如说,你使用了支付宝的即时付款机制,那么在用户付款的时候服务器与服务器之间会有一个回馈机制,用于支付宝通知我们的应用用户已经成功付款,这个时候我们可能需要排除csrf对反馈路由的保护。那么我们可以在VerifyCsrfToken中间件中修改$except属性中增加一条规则:
<?phpnamespace App\Http\Middleware;use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;class VerifyCsrfToken extends BaseVerifier{ /** * The URIs that should be excluded from CSRF verification. * * @var array */ protected $except = [ 'alipay/*', ];}
laravel的VerifyCsrfToken中间件不仅允许通过表单中验证_token参数,它也允许通过请求头去进行csrf验证,它会验证请求头中的X-CSRF-TOKEN值是否与会话的token值匹配,所以你可以这么做,存储token到meta中:
<meta name="csrf-token" content="{{ csrf_token() }}" >
一旦你定义了meta标签,你可以使用像jquery类似的框架去添加token到所有请求的头部:
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } })
laravel自动存储了CSRF token 到 cookie中并被命名为 XSRF-TOKEN, 你可以在每次请求的请求头里引入X-XSRF-TOKEN并将其值设置为 XSRF-TOKEN的cookie值来通过csrf验证。有一些javascript框架里已经自动做了这些,像 angularjs. 如果你没有引入这些前端框架,你可能需要自己手动去做了:
fetch('/user/password', { method: 'POST', headers: { 'X-XSRF-TOKEN': } })
绑定模型的路由提供了一种便利的方式去注入模型实例到路由中,比如,你可以通过传递id,来注入匹配id的用户的整个模型到路由中。
laravel会自动的解析定义在路由或者控制器中的Eloquent模型, 根据变量名与参数名匹配的,比如api/users/{user} 匹配 $user变量:
Route::get('api/users/{user}', function (App\User $user) { return $user->email; });
在上面的例子中,$user是根据url中{user}片段的值进行实例生成的.这种绑定模型到路由一般都是默认根据id进行匹配注入实例。比如说 users/1,匹配到的就是id = 1的用户实例。如果没有匹配的实例,则会返回404。
如果你不想用id去绑定模型到路由,laravel提供了一种可自定义的方式,你只需要在相应的模型里重写getRouteKeyName方法就行了,比如我们用名字来代替id注入模型到路由:
public function getRouteKeyName() { return 'name';}
这样在路由url中就是类似这种形式了 users/wang
如果需要注册一种显式的模型绑定到路由,你需要使路由的model方法去指定类与参数的映射。并且你应该在路由服务的boot方法中进行绑定注册操作:
public function boot(Router $router) { parent::boot($router); $router->model('user', 'App\User');}
这样,在routes.php文件中注册的路由如果使用了{user}的命名路由就可以自动绑定到模型:
$router->get('profile/{user}', function (App\User $user) { // });
如果你想自定义解析返回实例的逻辑,那么你需要使用Route::bind方法,该方法第一个参数为绑定url的参数名,第二个参数为Closure, 闭包中会接收一个参数,这个参数是url中对应参数片段的值,你应该在闭包中返回解析后的实例:
$router->bind('user', function ($value) { return App\User::where('name', $value)->first(); });
如果你想要自定义无法匹配实例时的行为,你可以向model方法传递第三个参数,该参数是一个闭包函数,它将在无法匹配到实例时执行:
$router->model('user', 'App\User', function () { throw new NotFoundHttpException;});
由于HTML的表单不能支持像PUT,PATCH或者DELETE的请求方式,所以,当需要访问类似的路由时,你需要在表单中增加一个隐藏的字段_method,用来表明你真实的表单请求方式:
<form action=“/foo/bar" method="POST"> <input type="hidden" name="_method" value="PUT"> <input type="hidden" name="_token" value="{{ csrf_token() }}"></form>
laravel也提供了便捷生成隐藏字段_method的方法,你可以使用method_field帮助方法:
<?php echo method_field(); ?>
使用blade模板引擎可以直接这么用:
{{ method_field('PUT') }}
Route::current() 会返回一个Illuminate\Routing\Route的实例,它允许你在当前路由内处理相关请求:
$route = Route::current();$name = $route->getName();$actionName = $route->getActionName();
当然你也可以通过Routefacade去访问路由的name或action:
$name = Route::currentRouteName();$action = Route::currentRouteAction();