212 lines
7.1 KiB
Markdown
212 lines
7.1 KiB
Markdown
---
|
||
layout: wiki
|
||
wiki: laravel #项目名
|
||
date: 2023-12-28 16:56
|
||
categories: [Laravel]
|
||
title: 解析路由
|
||
---
|
||
|
||
{%quot el:h2 解析路由%}
|
||
|
||
上面说到,请求经过中间件之后,最终调用`dispatchToRouter()`方法,接下来分析`dispatchToRouter()`方法的实现。
|
||
```php
|
||
protected function dispatchToRouter()
|
||
{
|
||
return function ($request) {
|
||
// 将request绑定到容器中
|
||
$this->app->instance('request', $request);
|
||
// 路由匹配
|
||
return $this->router->dispatch($request);
|
||
};
|
||
}
|
||
```
|
||
### 查看dispatch()方法
|
||
源码,
|
||
```php
|
||
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()`方法,
|
||
```php
|
||
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()方法
|
||
```php
|
||
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()方法
|
||
返回响应内容
|
||
```php
|
||
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()方法
|
||
```php
|
||
# -----------------------------------------------------------
|
||
# 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()`方法
|
||
```php
|
||
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`对象从容器中取出传参
|
||
```php
|
||
protected function handleCarry($carry)
|
||
{
|
||
return $carry instanceof Responsable
|
||
? $carry->toResponse($this->getContainer()->make(Request::class))
|
||
: $carry;
|
||
}
|
||
``` |