7.1 KiB
7.1 KiB
layout | wiki | date | categories | title | |
---|---|---|---|---|---|
wiki | laravel | 2023-12-28 16:56 |
|
解析路由 |
{%quot el:h2 解析路由%}
上面说到,请求经过中间件之后,最终调用dispatchToRouter()
方法,接下来分析dispatchToRouter()
方法的实现。
protected function dispatchToRouter()
{
return function ($request) {
// 将request绑定到容器中
$this->app->instance('request', $request);
// 路由匹配
return $this->router->dispatch($request);
};
}
查看dispatch()方法
源码,
public function dispatch(Request $request)
{
// 将请求给Router类的currentRequest变量
$this->currentRequest = $request;
// 继续看下面的dispatchToRoute()方法
return $this->dispatchToRoute($request);
}
public function dispatchToRoute(Request $request)
{
return $this->runRoute($request, $this->findRoute($request));
}
先看findRoute()
方法,
protected function findRoute($request)
{
// 查找匹配的路由,如果路由不存在则抛出NotFoundHttpException异常
$this->current = $route = $this->routes->match($request);
// 绑定路由到容器中
$route->setContainer($this->container);
// 将路由绑定到容器中
$this->container->instance(Route::class, $route);
return $route;
}
# -----------------------------------------
// $this->routes 为RouteCollection实例
public function __construct(Dispatcher $events, Container $container = null)
{
$this->events = $events;
$this->routes = new RouteCollection;
$this->container = $container ?: new Container;
}
# -------------------------------------------
// match方法
public function match(Request $request)
{
// 获取对应请求方法的所有路由
$routes = $this->get($request->getMethod());
// First, we will see if we can find a matching route for this current request
// method. If we can, great, we can just return it so that it can be called
// by the consumer. Otherwise we will check for routes with another verb.
$route = $this->matchAgainstRoutes($routes, $request);
return $this->handleMatchedRoute($request, $route);
}
查看runRoute()方法
protected function runRoute(Request $request, Route $route)
{
$request->setRouteResolver(function () use ($route) {
return $route;
});
// 触发RouteMatched事件
$this->events->dispatch(new RouteMatched($route, $request));
// 返回响应内容
return $this->prepareResponse($request,
$this->runRouteWithinStack($route, $request)
);
}
runRouteWithinStack()方法
返回响应内容
protected function runRouteWithinStack(Route $route, Request $request)
{
$shouldSkipMiddleware = $this->container->bound('middleware.disable') &&
$this->container->make('middleware.disable') === true;
// 这里的中间件可以是全局中间件,也可以是路由中间件
$middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route);
// 这里又执行了一次在处理请求时的Pipeline类,只是最后传的匿名函数不同
// 最终返回响应内容给toResponse()方法
return (new Pipeline($this->container))
->send($request)
->through($middleware)
->then(function ($request) use ($route) {
return $this->prepareResponse(
$request, $route->run()
);
});
}
#--------------------------------------------------------------------
// run方法
public function run()
{
$this->container = $this->container ?: new Container;
try {
/**
* 判断是否是控制器方法
* 是则运行控制器的方法
*/
if ($this->isControllerAction()) {
/**
* protected function runController()
* {
* return $this->controllerDispatcher()->dispatch(
* $this, $this->getController(), $this->getControllerMethod()
* );
* }
*/
return $this->runController();
}
// 如果不是,则运行回调函数
return $this->runCallable();
} catch (HttpResponseException $e) {
return $e->getResponse();
}
}
prepareResponse()方法
# -----------------------------------------------------------
# prepareResponse()方法,第一个是请求对象,第二个是$this->runRouteWithinStack($route, $request)方法返回的响应内容
public function prepareResponse($request, $response)
{
return static::toResponse($request, $response);
}
// toResponse()方法
// 判断响应内容是那种类型,然后实例化对应的响应对象
public static function toResponse($request, $response)
{
if ($response instanceof Responsable) {
$response = $response->toResponse($request);
}
if ($response instanceof PsrResponseInterface) {
$response = (new HttpFoundationFactory)->createResponse($response);
} elseif ($response instanceof Model && $response->wasRecentlyCreated) {
$response = new JsonResponse($response, 201);
} elseif ($response instanceof Stringable) {
$response = new Response($response->__toString(), 200, ['Content-Type' => 'text/html']);
} elseif (! $response instanceof SymfonyResponse &&
($response instanceof Arrayable ||
$response instanceof Jsonable ||
$response instanceof ArrayObject ||
$response instanceof JsonSerializable ||
$response instanceof \stdClass ||
is_array($response))) {
$response = new JsonResponse($response);
} elseif (! $response instanceof SymfonyResponse) {
$response = new Response($response, 200, ['Content-Type' => 'text/html']);
}
if ($response->getStatusCode() === Response::HTTP_NOT_MODIFIED) {
$response->setNotModified();
}
return $response->prepare($request);
}
最终dispatchToRouter()
方法返回一个Response对象,然后执行carry()
方法
protected function carry()
{
return function ($stack, $pipe) {
return function ($passable) use ($stack, $pipe) {
try {
// 省略...
$carry = method_exists($pipe, $this->method)
? $pipe->{$this->method}(...$parameters)
: $pipe(...$parameters);
// 最终return handleCarry这个方法
// carry是返回的Response对象
return $this->handleCarry($carry);
} catch (Throwable $e) {
return $this->handleException($passable, $e);
}
};
};
}
查看handleCarry()方法
上面内容跑完之后,最终返回的就是一个Response
对象,然后响应对象调用toResponse
方法,将Request
对象从容器中取出传参
protected function handleCarry($carry)
{
return $carry instanceof Responsable
? $carry->toResponse($this->getContainer()->make(Request::class))
: $carry;
}