Laravel核心解读Response

Laravel核心解读Response

内容导读

收集整理的这篇技术教程文章主要介绍了Laravel核心解读Response,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含8309字,纯文字阅读大概需要12分钟

内容图文

这篇文章主要介绍了关于Laravel核心解读Response,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下

Response

前面两节我们分别讲了Laravel的控制器和Request对象,在讲Request对象的那一节我们看了Request对象是如何被创建出来的以及它支持的方法都定义在哪里,讲控制器时我们详细地描述了如何找到Request对应的控制器方法然后执行处理程序的,本节我们就来说剩下的那一部分,控制器方法的执行结果是如何被转换成响应对象Response然后返回给客户端的。

创建Response

让我们回到Laravel执行路由处理程序返回响应的代码块:

namespace IlluminateRouting;class Router implements RegistrarContract, BindingRegistrar{



 protected function runRoute(Request $request, Route $route)

{



$request->setRouteResolver(function () use ($route) {





return $route;



});



$this->events->dispatch(new EventsRouteMatched($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方法里是最终执行路由处理程序(控制器方法或者闭包处理程序)的地方,通过上面的代码我们也可以看到执行的结果会传递给RouterprepareResponse方法,当程序流返回到runRoute里后又执行了一次prepareResponse方法得到了要返回给客户端的Response对象, 下面我们就来详细看一下prepareResponse方法。

class Router implements RegistrarContract, BindingRegistrar{

/**

 * 通过给定值创建Response对象

 *

 * @param
SymfonyComponentHttpFoundationRequest
$request

 * @param
mixed
$response

 * @return IlluminateHttpResponse|IlluminateHttpJsonResponse

 */

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);

}}

在上面的代码中我们看到有三种Response:

Class NameRepresentation
PsrResponseInterface(PsrHttpMessageResponseInterface的别名)Psr规范中对服务端响应的定义
IlluminateHttpJsonResponse (SymfonyComponentHttpFoundationResponse的子类)Laravel中对服务端JSON响应的定义
IlluminateHttpResponse (SymfonyComponentHttpFoundationResponse的子类)Laravel中对普通的非JSON响应的定义

通过prepareResponse中的逻辑可以看到,无论路由执行结果返回的是什么值最终都会被Laravel转换为成一个Response对象,而这些对象都是SymfonyComponentHttpFoundationResponse类或者其子类的对象。从这里也就能看出来跟Request一样Laravel的Response也是依赖Symfony框架的HttpFoundation组件来实现的。

我们来看一下SymfonyComponentHttpFoundationResponse的构造方法:

namespace SymfonyComponentHttpFoundation;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属性里,该属性的值就是返回给客户端的响应的响应内容。

设置Response headers

生成Response对象后就要执行对象的prepare方法了,该方法定义在SymfonyComponentHttpFoundationResposne类中,其主要目的是对Response进行微调使其能够遵从HTTP/1.1协议(RFC 2616)。

namespace SymfonyComponentHttpFoundation;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里针对各种情况设置了相应的response header 比如Content-TypeContent-Length等等这些我们常见的首部字段。

发送Response

创建并设置完Response后它会流经路由和框架中间件的后置操作,在中间件的后置操作里一般都是对Response进行进一步加工,最后程序流回到Http Kernel那里, Http Kernel会把Response发送给客户端,我们来看一下这部分的代码。

//入口文件public/index.php$kernel = $app->make(IlluminateContractsHttpKernel::class);$response = $kernel->handle(

$request = IlluminateHttpRequest::capture());$response->send();$kernel->terminate($request, $response);
namespace SymfonyComponentHttpFoundation;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的逻辑就非常好理解了,把之前设置好的那些headers设置到HTTP响应的首部字段里,Content会echo后被设置到HTTP响应的主体实体中。最后PHP会把完整的HTTP响应发送给客户端。

send响应后Http Kernel会执行terminate方法调用terminate中间件里的terminate方法,最后执行应用的termiate方法来结束整个应用生命周期(从接收请求开始到返回响应结束)。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

Laravel核心解读Request

以上就是Laravel核心解读Response的详细内容,更多请关注Gxl网其它相关文章!

内容总结

以上是为您收集整理的Laravel核心解读Response全部内容,希望文章能够帮你解决Laravel核心解读Response所遇到的程序开发问题。 如果觉得技术教程内容还不错,欢迎将网站推荐给程序员好友。

内容备注

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。


本文关键词:

联系我们

在线咨询:点击这里给我发消息

邮件:w420220301@qq.com