Laravel Reponse响应客户端示例详解(5)

/** * Prepares the Response before it is sent to the client. * * This method tweaks the Response to ensure that it is * compliant with RFC 2616. Most of the changes are based on * the Request that is "associated" with this Response. * * @return $this */ // 总的来说就是设置各种响应头 注意此时并未发送响应 public function prepare(Request $request) { $headers = $this->headers; // 如果是100 204 304系列的状态码 就删除响应数据 删除对应的数据头 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->getPreferredFormat(); 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($headers->get('Cache-Control'), 'no-cache')) { $headers->set('pragma', 'no-cache'); $headers->set('expires', -1); } $this->ensureIEOverSSLCompatibility($request); if ($request->isSecure()) { foreach ($headers->getCookies() as $cookie) { $cookie->setSecureDefault(true); } } return $this; } // 至此我们的响应封装好了 等待发送给客户端 // 在发送之前 还要将响应逐步返回 // 值得注意的是 如果你给此路由设置了后置中间件 可能如下 public function handle($request, Closure $next) { // 此时拿到的$response就是我们上面响应好了一切 准备发送的响应了 希望你能理解后置中间件的作用了 $response = $next($request); // header方法位于ResponseTrait $response->header('Server', 'xy'); return $response; }

拿到准备好的响应了,逐级向调用栈行层返回,关系如下

响应返回到Router::runRoute方法 再返回到Router::dispatchToRoute方法 再返回到Router::dispatch方法 再返回到Illuminate\Foundation\Http::sendRequestThroughRouter方法 (注意只要是通过了管道都要注意中间件的类型) 最终返回到index.php中 $response = $kernel->handle( $request = Illuminate\Http\Request::capture() ); $response->send(); $kernel->terminate($request, $response);

我们来看send方法 Symfony\Component\HttpFoundation\Response::send

public function send() { // 先发送响应头 $this->sendHeaders(); // 再发送响应主体 $this->sendContent(); if (\function_exists('fastcgi_finish_request')) { fastcgi_finish_request(); } elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { static::closeOutputBuffers(0, true); } return $this; } public function sendHeaders() { // headers have already been sent by the developer if (headers_sent()) { return $this; } // headers foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) { $replace = 0 === strcasecmp($name, 'Content-Type'); foreach ($values as $value) { // 将之前设置的各种头发送出去 header($name.': '.$value, $replace, $this->statusCode); } } // cookies foreach ($this->headers->getCookies() as $cookie) { // 告诉客户端要设置的cookie header('Set-Cookie: '.$cookie, false, $this->statusCode); } // status // 最后发送个status header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode); return $this; } // 发送响应内容 public function sendContent() { // 想笑吗 就是这么简单 echo $this->content; return $this; } // 至此真的响应了客户端了

$kernel->terminate($request, $response);

Illuminate\Foundation\Http\Kernel::terminate方法

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/031c11b01a1a2900bf9716186b4e5059.html