この記事では、Laravel における Response のコアな解釈を中心に紹介しますが、これは一定の参考値がありますので、共有します。必要な友人は参考にしてください。
We前の 2 つのセクションで説明したとおり、Laravel のコントローラーと Request オブジェクトについてそれぞれ説明しました。Request オブジェクトに関するセクションでは、Request オブジェクトがどのように作成されるか、およびそれがサポートするメソッドがどこで定義されているかを説明しました。コントローラーについて説明するときは、 Request に対応するコントローラー メソッドを検索してハンドラーを実行する方法について詳しく説明しましたが、このセクションでは残りの部分、コントローラー メソッドの実行結果が応答オブジェクト Response に変換されてクライアントに返される方法について説明します。 。
Laravel がルート ハンドラーを実行してレスポンスを返すコード ブロックに戻りましょう:
namespace Illuminate\Routing; class Router implements RegistrarContract, BindingRegistrar { protected function runRoute(Request $request, Route $route) { $request->setRouteResolver(function () use ($route) { return $route; }); $this->events->dispatch(new Events\RouteMatched($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; //收集路由和控制器里应用的中间件 $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() ); }); } }
これについてはコントローラーに関するセクションですでに説明しました。 runRouteWithinStack
メソッドは、ルーティング ハンドラー (コントローラー メソッドまたはクロージャー ハンドラー) が最終的に実行される場所です。上記のコードを通じて、実行結果が Router
に渡されることもわかります。 ##prepareResponse メソッド、プログラム フローが
runRoute に戻ると、クライアントに返される Response オブジェクトを取得するために
prepareResponse メソッドが再度実行されます。次にこれを実行しましょう。
prepareResponse メソッドを詳しく見てみましょう。
class Router implements RegistrarContract, BindingRegistrar { /** * 通过给定值创建Response对象 * * @param \Symfony\Component\HttpFoundation\Request $request * @param mixed $response * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse */ public function prepareResponse($request, $response) { return static::toResponse($request, $response); } 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 SymfonyResponse && ($response instanceof Arrayable || $response instanceof Jsonable || $response instanceof ArrayObject || $response instanceof JsonSerializable || is_array($response))) { $response = new JsonResponse($response); } elseif (! $response instanceof SymfonyResponse) { $response = new Response($response); } if ($response->getStatusCode() === Response::HTTP_NOT_MODIFIED) { $response->setNotModified(); } return $response->prepare($request); } }上記のコードでは、次の 3 種類の応答が表示されます。
表現 | |
---|---|
IlluminateHttpJsonResponse (SymfonyComponentHttpFoundationResponse のサブクラス) | |
IlluminateHttpResponse (SymfonyComponentHttpFoundationResponse のサブクラス) | |
HttpFoundation コンポーネントに依存していることがわかります。
SymfonyComponentHttpFoundationResponse の構築メソッドを見てみましょう:
namespace Symfony\Component\HttpFoundation; class Response { public function __construct($content = '', $status = 200, $headers = array()) { $this->headers = new ResponseHeaderBag($headers); $this->setContent($content); $this->setStatusCode($status); $this->setProtocolVersion('1.0'); } //设置响应的Content public function setContent($content) { if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable(array($content, '__toString'))) { throw new \UnexpectedValueException(sprintf('The Response content must be a string or object implementing __toString(), "%s" given.', gettype($content))); } $this->content = (string) $content; return $this; } }したがって、ルーティング ハンドラーの戻り値は、Response オブジェクトの作成時にオブジェクトの content 属性に設定され、この属性の値は、クライアントの応答の応答コンテンツに返されます。 Set Response headersResponse オブジェクトを生成した後、オブジェクトの
Symfony\Component\HttpFoundation で定義されています\ResposneClass の主な目的は、HTTP/1.1 プロトコル (RFC 2616) に準拠できるように応答を微調整することです。
namespace Symfony\Component\HttpFoundation; class Response { //在响应被发送给客户端之前对其进行修订使其能遵从HTTP/1.1协议 public function prepare(Request $request) { $headers = $this->headers; if ($this->isInformational() || $this->isEmpty()) { $this->setContent(null); $headers->remove('Content-Type'); $headers->remove('Content-Length'); } else { // Content-type based on the Request if (!$headers->has('Content-Type')) { $format = $request->getRequestFormat(); if (null !== $format && $mimeType = $request->getMimeType($format)) { $headers->set('Content-Type', $mimeType); } } // Fix Content-Type $charset = $this->charset ?: 'UTF-8'; if (!$headers->has('Content-Type')) { $headers->set('Content-Type', 'text/html; charset='.$charset); } elseif (0 === stripos($headers->get('Content-Type'), 'text/') && false === stripos($headers->get('Content-Type'), 'charset')) { // add the charset $headers->set('Content-Type', $headers->get('Content-Type').'; charset='.$charset); } // Fix Content-Length if ($headers->has('Transfer-Encoding')) { $headers->remove('Content-Length'); } if ($request->isMethod('HEAD')) { // cf. RFC2616 14.13 $length = $headers->get('Content-Length'); $this->setContent(null); if ($length) { $headers->set('Content-Length', $length); } } } // Fix protocol if ('HTTP/1.0' != $request->server->get('SERVER_PROTOCOL')) { $this->setProtocolVersion('1.1'); } // Check if we need to send extra expire info headers if ('1.0' == $this->getProtocolVersion() && false !== strpos($this->headers->get('Cache-Control'), 'no-cache')) { $this->headers->set('pragma', 'no-cache'); $this->headers->set('expires', -1); } $this->ensureIEOverSSLCompatibility($request); return $this; } }
prepare は、Content-Type、
Content-Length## など、さまざまな状況に対応する 応答ヘッダー
を設定します #Waitこれらの一般的なヘッダー フィールドの場合。 応答の送信
応答が作成および設定された後、応答はルーティングおよびフレームワーク ミドルウェアの後処理を通過します。ミドルウェアの後処理では、通常、応答はさらに続きます。処理され、最後にプログラムは HTTP カーネルに戻り、HTTP カーネルはクライアントに応答を送信します。コードのこの部分を見てみましょう。
//入口文件public/index.php $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); $response = $kernel->handle( $request = Illuminate\Http\Request::capture() ); $response->send(); $kernel->terminate($request, $response);
namespace Symfony\Component\HttpFoundation; class Response { public function send() { $this->sendHeaders(); $this->sendContent(); if (function_exists('fastcgi_finish_request')) { fastcgi_finish_request(); } elseif ('cli' !== PHP_SAPI) { static::closeOutputBuffers(0, true); } return $this; } //发送headers到客户端 public function sendHeaders() { // headers have already been sent by the developer if (headers_sent()) { return $this; } // headers foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) { foreach ($values as $value) { header($name.': '.$value, false, $this->statusCode); } } // status header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode); // cookies foreach ($this->headers->getCookies() as $cookie) { if ($cookie->isRaw()) { setrawcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly()); } else { setcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly()); } } return $this; } //发送响应内容到客户端 public function sendContent() { echo $this->content; return $this; } }send
のロジックは非常に分かりやすく、HTTP レスポンスのヘッダーフィールドにあらかじめ設定したヘッダーを設定すると、Content がエコーされて本体に設定されます。 HTTP レスポンス。最後に、PHP は完全な HTTP 応答をクライアントに送信します。
応答を送信した後、HTTP カーネルは terminate
メソッドを実行して終了ミドルウェアの
メソッドを呼び出し、最後にアプリケーションの termiate# を実行します。 ## 終了するメソッド アプリケーションのライフサイクル全体 (リクエストの受信からレスポンスの返しまで)。
上記がこの記事の全内容です。皆様の学習に少しでもお役に立てれば幸いです。その他の関連コンテンツについては、PHP 中国語 Web サイトをご覧ください。
関連する推奨事項:
Laravel コア解釈リクエスト
以上がResponse の Laravel コア解釈の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。