vitepress-blog/src/laravel/解析路由.md
2024-07-08 18:15:43 +09:00

212 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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;
}
```