久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      laravel路由是什么

      在laravel中,路由是外界訪問Laravel應(yīng)用程序的通路,或者說路由定義了Laravel的應(yīng)用程序向外界提供服務(wù)的具體方式。路由會(huì)將用戶的請(qǐng)求按照事先規(guī)劃的方案提交給指定的控制器和方法來進(jìn)行處理。

      laravel路由是什么

      本教程操作環(huán)境:windows7系統(tǒng)、Laravel6版,DELL G3電腦。

      路由是外界訪問Laravel應(yīng)用程序的通路或者說路由定義了Laravel的應(yīng)用程序向外界提供服務(wù)的具體方式:通過指定的URI、HTTP請(qǐng)求方法以及路由參數(shù)(可選)才能正確訪問到路由定義的處理程序。

      無論URI對(duì)應(yīng)的處理程序是一個(gè)簡(jiǎn)單的閉包還是說是控制器方法沒有對(duì)應(yīng)的路由外界都訪問不到他們

      今天我們就來看看Laravel是如何來設(shè)計(jì)和實(shí)現(xiàn)路由的。

      我們?cè)诼酚晌募锿ǔJ窍蛳旅孢@樣來定義路由的:

      Route::get('/user', 'UsersController@index');

      通過上面的路由我們可以知道,客戶端通過以HTTP GET方式來請(qǐng)求 URI "/user"時(shí),Laravel會(huì)把請(qǐng)求最終派發(fā)給UsersController類的index方法來進(jìn)行處理,然后在index方法中返回響應(yīng)給客戶端。

      上面注冊(cè)路由時(shí)用到的Route類在Laravel里叫門面(Facade),它提供了一種簡(jiǎn)單的方式來訪問綁定到服務(wù)容器里的服務(wù)router,F(xiàn)acade的設(shè)計(jì)理念和實(shí)現(xiàn)方式我打算以后單開博文來寫,在這里我們只要知道調(diào)用的Route這個(gè)門面的靜態(tài)方法都對(duì)應(yīng)服務(wù)容器里router這個(gè)服務(wù)的方法,所以上面那條路由你也可以看成是這樣來注冊(cè)的:

      app()->make('router')->get('user', 'UsersController@index');

      router這個(gè)服務(wù)是在實(shí)例化應(yīng)用程序Application時(shí)在構(gòu)造方法里通過注冊(cè)RoutingServiceProvider時(shí)綁定到服務(wù)容器里的:

      //bootstrap/app.php $app = new IlluminateFoundationApplication(     realpath(__DIR__.'/../') );  //Application: 構(gòu)造方法 public function __construct($basePath = null) {     if ($basePath) {         $this->setBasePath($basePath);     }      $this->registerBaseBindings();      $this->registerBaseServiceProviders();      $this->registerCoreContainerAliases(); }  //Application: 注冊(cè)基礎(chǔ)的服務(wù)提供器 protected function registerBaseServiceProviders() {     $this->register(new EventServiceProvider($this));      $this->register(new LogServiceProvider($this));      $this->register(new RoutingServiceProvider($this)); }  //IlluminateRoutingRoutingServiceProvider: 綁定router到服務(wù)容器 protected function registerRouter() {     $this->app->singleton('router', function ($app) {         return new Router($app['events'], $app);     }); }

      通過上面的代碼我們知道了Route調(diào)用的靜態(tài)方法都對(duì)應(yīng)于IlluminateRoutingRouter類里的方法,Router這個(gè)類里包含了與路由的注冊(cè)、尋址、調(diào)度相關(guān)的方法。

      下面我們從路由的注冊(cè)、加載、尋址這幾個(gè)階段來看一下laravel里是如何實(shí)現(xiàn)這些的。

      路由加載

      注冊(cè)路由前需要先加載路由文件,路由文件的加載是在AppProvidersRouteServiceProvider這個(gè)服務(wù)器提供者的boot方法里加載的:

      class RouteServiceProvider extends ServiceProvider {     public function boot()     {         parent::boot();     }      public function map()     {         $this->mapApiRoutes();          $this->mapWebRoutes();     }      protected function mapWebRoutes()     {         Route::middleware('web')              ->namespace($this->namespace)              ->group(base_path('routes/web.php'));     }      protected function mapApiRoutes()     {         Route::prefix('api')              ->middleware('api')              ->namespace($this->namespace)              ->group(base_path('routes/api.php'));     } }
      namespace IlluminateFoundationSupportProviders;  class RouteServiceProvider extends ServiceProvider {      public function boot()     {         $this->setRootControllerNamespace();          if ($this->app->routesAreCached()) {             $this->loadCachedRoutes();         } else {             $this->loadRoutes();              $this->app->booted(function () {                 $this->app['router']->getRoutes()->refreshNameLookups();                 $this->app['router']->getRoutes()->refreshActionLookups();             });         }     }      protected function loadCachedRoutes()     {         $this->app->booted(function () {             require $this->app->getCachedRoutesPath();         });     }      protected function loadRoutes()     {         if (method_exists($this, 'map')) {             $this->app->call([$this, 'map']);         }     } }  class Application extends Container implements ApplicationContract, HttpKernelInterface {     public function routesAreCached()     {         return $this['files']->exists($this->getCachedRoutesPath());     }      public function getCachedRoutesPath()     {         return $this->bootstrapPath().'/cache/routes.php';     } }

      laravel 首先去尋找路由的緩存文件,沒有緩存文件再去進(jìn)行加載路由。緩存文件一般在 bootstrap/cache/routes.php 文件中。
      方法loadRoutes會(huì)調(diào)用map方法來加載路由文件里的路由,map這個(gè)函數(shù)在AppProvidersRouteServiceProvider類中,這個(gè)類繼承自IlluminateFoundationSupportProvidersRouteServiceProvider。通過map方法我們能看到laravel將路由分為兩個(gè)大組:api、web。這兩個(gè)部分的路由分別寫在兩個(gè)文件中:routes/web.php、routes/api.php。

      Laravel5.5里是把路由分別放在了幾個(gè)文件里,之前的版本是在app/Http/routes.php文件里。放在多個(gè)文件里能更方便地管理API路由和與WEB路由

      路由注冊(cè)

      我們通常都是用Route這個(gè)Facade調(diào)用靜態(tài)方法get, post, head, options, put, patch, delete……等來注冊(cè)路由,上面我們也說了這些靜態(tài)方法其實(shí)是調(diào)用了Router類里的方法:

      public function get($uri, $action = null) {     return $this->addRoute(['GET', 'HEAD'], $uri, $action); }  public function post($uri, $action = null) {     return $this->addRoute('POST', $uri, $action); } ....

      可以看到路由的注冊(cè)統(tǒng)一都是由router類的addRoute方法來處理的:

      //注冊(cè)路由到RouteCollection protected function addRoute($methods, $uri, $action) {     return $this->routes->add($this->createRoute($methods, $uri, $action)); }  //創(chuàng)建路由 protected function createRoute($methods, $uri, $action) {     if ($this->actionReferencesController($action)) {         //controller@action類型的路由在這里要進(jìn)行轉(zhuǎn)換         $action = $this->convertToControllerAction($action);     }      $route = $this->newRoute(         $methods, $this->prefix($uri), $action     );      if ($this->hasGroupStack()) {         $this->mergeGroupAttributesIntoRoute($route);     }      $this->addWhereClausesToRoute($route);      return $route; }  protected function convertToControllerAction($action) {     if (is_string($action)) {         $action = ['uses' => $action];     }      if (! empty($this->groupStack)) {                 $action['uses'] = $this->prependGroupNamespace($action['uses']);     }          $action['controller'] = $action['uses'];      return $action; }

      注冊(cè)路由時(shí)傳遞給addRoute的第三個(gè)參數(shù)action可以閉包、字符串或者數(shù)組,數(shù)組就是類似['uses' => 'Controller@action', 'middleware' => '…']這種形式的。如果action是Controller@action類型的路由將被轉(zhuǎn)換為action數(shù)組, convertToControllerAction執(zhí)行完后action的內(nèi)容為:

      [     'uses' => 'AppHttpControllersSomeController@someAction',     'controller' => 'AppHttpControllersSomeController@someAction' ]

      可以看到把命名空間補(bǔ)充到了控制器的名稱前組成了完整的控制器類名,action數(shù)組構(gòu)建完成接下里就是創(chuàng)建路由了,創(chuàng)建路由即用指定的HTTP請(qǐng)求方法、URI字符串和action數(shù)組來創(chuàng)建IlluminateRoutingRoute類的實(shí)例:

      protected function newRoute($methods, $uri, $action) {     return (new Route($methods, $uri, $action))                 ->setRouter($this)                 ->setContainer($this->container); }

      路由創(chuàng)建完成后將Route添加到RouteCollection中去:

      protected function addRoute($methods, $uri, $action) {     return $this->routes->add($this->createRoute($methods, $uri, $action)); }

      router的$routes屬性就是一個(gè)RouteCollection對(duì)象,添加路由到RouteCollection對(duì)象時(shí)會(huì)更新RouteCollection對(duì)象的routes、allRoutes、nameList和actionList屬性

      class RouteCollection implements Countable, IteratorAggregate {     public function add(Route $route)     {         $this->addToCollections($route);          $this->addLookups($route);          return $route;     }          protected function addToCollections($route)     {         $domainAndUri = $route->getDomain().$route->uri();          foreach ($route->methods() as $method) {             $this->routes[$method][$domainAndUri] = $route;         }          $this->allRoutes[$method.$domainAndUri] = $route;     }          protected function addLookups($route)     {         $action = $route->getAction();          if (isset($action['as'])) {             //如果時(shí)命名路由,將route對(duì)象映射到以路由名為key的數(shù)組值中方便查找             $this->nameList[$action['as']] = $route;         }          if (isset($action['controller'])) {             $this->addToActionList($action, $route);         }     }  }

      RouteCollection的四個(gè)屬性

      routes中存放了HTTP請(qǐng)求方法與路由對(duì)象的映射:

      [     'GET' => [         $routeUri1 => $routeObj1         ...     ]     ... ]

      allRoutes屬性里存放的內(nèi)容時(shí)將routes屬性里的二位數(shù)組編程一位數(shù)組后的內(nèi)容:

      [     'GET' . $routeUri1 => $routeObj1     'GET' . $routeUri2 => $routeObj2     ... ]

      nameList是路由名稱與路由對(duì)象的一個(gè)映射表

      [     $routeName1 => $routeObj1     ... ]

      actionList是路由控制器方法字符串與路由對(duì)象的映射表

      [     'AppHttpControllersControllerOne@ActionOne' => $routeObj1 ]

      這樣就算注冊(cè)好路由了。

      路由尋址

      中間件的文章里我們說過HTTP請(qǐng)求在經(jīng)過Pipeline通道上的中間件的前置操作后到達(dá)目的地:

      //IlluminateFoundationHttpKernel class Kernel implements KernelContract {     protected function sendRequestThroughRouter($request)     {         $this->app->instance('request', $request);          Facade::clearResolvedInstance('request');          $this->bootstrap();          return (new Pipeline($this->app))                     ->send($request)                     ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)                     ->then($this->dispatchToRouter());     }          protected function dispatchToRouter()     {         return function ($request) {             $this->app->instance('request', $request);              return $this->router->dispatch($request);         };     }      }

      上面代碼可以看到Pipeline的destination就是dispatchToRouter函數(shù)返回的閉包:

      $destination = function ($request) {     $this->app->instance('request', $request);     return $this->router->dispatch($request); };

      在閉包里調(diào)用了router的dispatch方法,路由尋址就發(fā)生在dispatch的第一個(gè)階段findRoute里:

      class Router implements RegistrarContract, BindingRegistrar {         public function dispatch(Request $request)     {         $this->currentRequest = $request;          return $this->dispatchToRoute($request);     }          public function dispatchToRoute(Request $request)     {         return $this->runRoute($request, $this->findRoute($request));     }          protected function findRoute($request)     {         $this->current = $route = $this->routes->match($request);          $this->container->instance(Route::class, $route);          return $route;     }      }

      尋找路由的任務(wù)由 RouteCollection 負(fù)責(zé),這個(gè)函數(shù)負(fù)責(zé)匹配路由,并且把 request 的 url 參數(shù)綁定到路由中:

      class RouteCollection implements Countable, IteratorAggregate {     public function match(Request $request)     {         $routes = $this->get($request->getMethod());          $route = $this->matchAgainstRoutes($routes, $request);          if (! is_null($route)) {             //找到匹配的路由后,將URI里的路徑參數(shù)綁定賦值給路由(如果有的話)             return $route->bind($request);         }          $others = $this->checkForAlternateVerbs($request);          if (count($others) > 0) {             return $this->getRouteForMethods($request, $others);         }          throw new NotFoundHttpException;     }      protected function matchAgainstRoutes(array $routes, $request, $includingMethod = true)     {         return Arr::first($routes, function ($value) use ($request, $includingMethod) {             return $value->matches($request, $includingMethod);         });     } }  class Route {     public function matches(Request $request, $includingMethod = true)     {         $this->compileRoute();          foreach ($this->getValidators() as $validator) {             if (! $includingMethod && $validator instanceof MethodValidator) {                 continue;             }              if (! $validator->matches($this, $request)) {                 return false;             }         }          return true;     } }

      $routes = $this->get($request->getMethod());會(huì)先加載注冊(cè)路由階段在RouteCollection里生成的routes屬性里的值,routes中存放了HTTP請(qǐng)求方法與路由對(duì)象的映射。

      然后依次調(diào)用這堆路由里路由對(duì)象的matches方法, matches方法, matches方法里會(huì)對(duì)HTTP請(qǐng)求對(duì)象進(jìn)行一些驗(yàn)證,驗(yàn)證對(duì)應(yīng)的Validator是:UriValidator、MethodValidator、SchemeValidator、HostValidator。
      在驗(yàn)證之前在$this->compileRoute()里會(huì)將路由的規(guī)則轉(zhuǎn)換成正則表達(dá)式。

      UriValidator主要是看請(qǐng)求對(duì)象的URI是否與路由的正則規(guī)則匹配能匹配上:

      class UriValidator implements ValidatorInterface {     public function matches(Route $route, Request $request)     {         $path = $request->path() == '/' ? '/' : '/'.$request->path();          return preg_match($route->getCompiled()->getRegex(), rawurldecode($path));     } }

      MethodValidator驗(yàn)證請(qǐng)求方法, SchemeValidator驗(yàn)證協(xié)議是否正確(http|https), HostValidator驗(yàn)證域名, 如果路由中不設(shè)置host屬性,那么這個(gè)驗(yàn)證不會(huì)進(jìn)行。

      一旦某個(gè)路由通過了全部的認(rèn)證就將會(huì)被返回,接下來就要將請(qǐng)求對(duì)象URI里的路徑參數(shù)綁定賦值給路由參數(shù):

      路由參數(shù)綁定

      class Route {     public function bind(Request $request)     {         $this->compileRoute();          $this->parameters = (new RouteParameterBinder($this))                         ->parameters($request);          return $this;     } }  class RouteParameterBinder {     public function parameters($request)     {         $parameters = $this->bindPathParameters($request);          if (! is_null($this->route->compiled->getHostRegex())) {             $parameters = $this->bindHostParameters(                 $request, $parameters             );         }          return $this->replaceDefaults($parameters);     }          protected function bindPathParameters($request)     {             preg_match($this->route->compiled->getRegex(), '/'.$request->decodedPath(), $matches);              return $this->matchToKeys(array_slice($matches, 1));     }          protected function matchToKeys(array $matches)     {         if (empty($parameterNames = $this->route->parameterNames())) {             return [];         }          $parameters = array_intersect_key($matches, array_flip($parameterNames));          return array_filter($parameters, function ($value) {             return is_string($value) && strlen($value) > 0;         });     } }

      賦值路由參數(shù)完成后路由尋址的過程就結(jié)束了,結(jié)下來就該運(yùn)行通過匹配路由中對(duì)應(yīng)的控制器方法返回響應(yīng)對(duì)象了。

      class Router implements RegistrarContract, BindingRegistrar {         public function dispatch(Request $request)     {         $this->currentRequest = $request;          return $this->dispatchToRoute($request);     }          public function dispatchToRoute(Request $request)     {         return $this->runRoute($request, $this->findRoute($request));     }          protected function runRoute(Request $request, Route $route)     {         $request->setRouteResolver(function () use ($route) {             return $route;         });          $this->events->dispatch(new EventsRouteMatched($route, $request));          return $this->prepareResponse($request,             $this->runRouteWithinStack($route, $request)         );     }          protected function runRouteWithinStack(Route $route, Request $request)     {         $shouldSkipMiddleware = $this->container->bound('middleware.disable') &&                             $this->container->make('middleware.disable') === true;     //收集路由和控制器里應(yīng)用的中間件         $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route);          return (new Pipeline($this->container))                     ->send($request)                     ->through($middleware)                     ->then(function ($request) use ($route) {                         return $this->prepareResponse(                             $request, $route->run()                         );                     });          }      }  namespace IlluminateRouting; class Route {     public function run()     {         $this->container = $this->container ?: new Container;         try {             if ($this->isControllerAction()) {                 return $this->runController();             }             return $this->runCallable();         } catch (HttpResponseException $e) {             return $e->getResponse();         }     }  }

      這里我們主要介紹路由相關(guān)的內(nèi)容,runRoute的過程通過上面的源碼可以看到其實(shí)也很復(fù)雜, 會(huì)收集路由和控制器里的中間件,將請(qǐng)求通過中間件過濾才會(huì)最終到達(dá)目的地路由,執(zhí)行目的路由地run()方法,里面會(huì)判斷路由對(duì)應(yīng)的是一個(gè)控制器方法還是閉包然后進(jìn)行相應(yīng)地調(diào)用,最后把執(zhí)行結(jié)果包裝成Response對(duì)象返回給客戶端。這個(gè)過程還會(huì)涉及到我們以前介紹過的中間件過濾、服務(wù)解析、依賴注入方面的信息。

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)