💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
请求处理 return $this->app->route->dispatch($request, $withRoute); 这里就是处理整个业务的核心,之前的事件注册,路由注册,中间件注册,都会在这里执行。可能会涉及很多细节,但在这里不会细说,主要看一下整个分发的流程。看一下 dispatch 方法的代码 public function dispatch(Request $request, $withRoute = null) { $this->request = $request; // 1 $this->host = $this->request->host(true); // 2 $this->init(); // 3 if ($withRoute) { $checkCallback = function () use ($request, $withRoute) { $withRoute(); return $this->check(); }; if ($this->config['route_check_cache']) { $dispatch = $this->cache ->tag('route_cache') ->remember($this->getRouteCacheKey($request), $checkCallback); } else { $dispatch = $checkCallback(); } } else { $dispatch = $this->url($this->path()); } // 4 $dispatch->init($this->app); $this->app->middleware->add(function () use ($dispatch) { try { $response = $dispatch->run(); } catch (HttpResponseException $exception) { $response = $exception->getResponse(); } return $response; }); return $this->app->middleware->dispatch($request); } 按照 1 ~ 4 步骤进行说明 获取域名不含端口号 初始化 route 的初始化 加载配置文件 route.php 路由是否延迟解析 设置路由缓存 如果生成了路由缓存文件就加载路由缓存文件 => runtime 目录下的 route.php 是否开启路由 开启路由缓存 ,加载路由文件并且检测 URL,设置路由缓存 key 的还会将对应路由缓存起来。 注意的是,remember 方法会执行闭包,所以存储的并不是闭包,而是 dispatch\url 对象 获取路由缓存的 key,这个是在配置文件设置的,还必须是设置闭包。 如果没有开启路由 直接解析 URL dispatch 初始化 因为 $dispatch instanceof dispatch\Controller 所以主要初始化工作在 Controller 里面 将调度追加到中间件 middleware queue 队列中,所以这一步最近才会执行 中间件调度执行 未启用路由 当前所在 think\Route 类中,再往下讲之前,先来看一下 url 这个方法。 public function url(string $url): UrlDispatch { return new UrlDispatch($this->request, $this->group, $url); } 这段代码很重要,因为请求在没有启用路由的情况是由它处理。$this->group 属性呢就是在当前类实例化的时候设置的 think\route\Domain 域名路由类。$url 是从 pathinfo 信息中获取的。了解了这些信息之后,直接看到步骤 4,因为上面的步骤最终目的都是获得这个 dispatch 对象。 启用路由的情况 启动路由的情况会产生另外一个 Dispatch 对象 think\route\dispatch\Callback,为什么会产生两个不同对象,具体细节在之后的路由解析中会详细介绍,先跳过细节,看看整个过程是如何处理的。下面会分别介绍两个对象的处理。 DisPatch 的初始化 上述两种情况下,获取控制和模块的方法是完全不一样。 前者是直接解析 URL 来获取,就是框架以前传统的方式 module/controller/index,然后解析出来。 后者是经过路由解析之后,才会获取相应模块的控制器,这部分有一定性能消耗。 所以对比来看,未启用路由性能比较高,但是还是推荐启用路由,这样比较易于管理。 Dispatch 执行 因为 Dispatch run 作为闭包被加入到中间的队列中之后,由中间件 Dispatch。关于中间执行可以参照上篇,这里需要知道的是 Dispatch 是被加到中间件队列末尾,是在最后执行的就可以了。 主要来看 $dispatch->run(),上文说的两个对象都是继承 Dispatch 对象的,所以到里面看看 run 方法。 public function run(): Response { if ($this->rule instanceof RuleItem && $this->request->method() == 'OPTIONS' && $this->rule->isAutoOptions()) { $rules = $this->rule->getRouter()->getRule($this->rule->getRule()); $allow = []; foreach ($rules as $item) { $allow[] = strtoupper($item->getMethod()); } return Response::create('', '', 204)->header(['Allow' => implode(', ', $allow)]); } $option = $this->rule->getOption(); // 数据自动验证 if (isset($option['validate'])) { $this->autoValidate($option['validate']); } $data = $this->exec(); return $this->autoResponse($data); } 启用路由和未启用路由完全是两种过程,启用理由设计到路由解析的过程,暂且搁置,后面详细说明。下面的过程是指的未启用路由的过程。 通过 URL 获取访问路径,例如 index/index 对于这样的 URL 默认会访问配置文件 route.php 的 controller_layer 所设置的目录下的类文件。框架默认设置的是 controller。创建框架的时候应该就可以看到了。 对于控制器而言可以设置控制器的中间件,对于控制器中间件作用范围应该是执行方法之前,控制器初始化后。 设置空控制器,默认是 Error,这个似乎和以前的版本是一样的。 这两种方式的区别,路由访问带来了一定的自由目录组织的能力,当然性能会有所损耗,Url 访问可能限制相对而言不是那么自由,比如对于初始化框架你只能限定在 controller 目录下创建类使用。当然这个是可以改变的,使用框架在初始化的先后循序上做一下改变,以应对框架的在 URL 解析上的规则,这个将会在下一篇事件机制上作出解答