Laravel Reponse响应客户端示例详解
前言
本篇文章逻辑较长,只说明和响应生命周期相关的必要代码。
本文主要内容顺序为:
1、执行上文管道中的then方法指定的闭包,路由的分发
2、在路由器中(Router类)找到请求($request也就是经过全局中间件处理的请求)匹配的路由规则
3、说明路由规则的加载(会跳转到框架的boot过程),注意这部分是在处理请求之前完成的,因为一旦当我们开始处理请求,就意味着所有的路由都应该已经加载好了,供我们的请求进行匹配
4、执行请求匹配到的路由逻辑
5、生成响应,并发送给客户端
6、最后生命周期的结束
7、基本响应类的使用
前文说道,如果一个请求顺利通过了全局中间件那么就会调用管道then方法中传入的闭包
protectedfunctionsendRequestThroughRouter($request) { $this->app->instance('request',$request); Facade::clearResolvedInstance('request'); $this->bootstrap(); //代码如下 return(newPipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware()?[]:$this->middleware) //此方法将当前请求挂载到容器,然后执行路由器的分发 ->then($this->dispatchToRouter()); } protectedfunctiondispatchToRouter() { returnfunction($request){ $this->app->instance('request',$request); return$this->router->dispatch($request); }; }
查看Illuminate\Routing\Router::dispatch方法
publicfunctiondispatch(Request$request) { $this->currentRequest=$request; //将请求分发到路由 //跳转到dispatchToRoute方法 return$this->dispatchToRoute($request); } publicfunctiondispatchToRoute(Request$request) { //先跳转到findRoute方法 return$this->runRoute($request,$this->findRoute($request)); } //见名之意通过给定的$request找到匹配的路由 protectedfunctionfindRoute($request) { //跳转到Illuminate\Routing\RouteCollection::match方法 $this->current=$route=$this->routes->match($request); $this->container->instance(Route::class,$route); return$route; }
查看Illuminate\Routing\RouteCollection::match方法
/** *Findthefirstroutematchingagivenrequest. * *@param\Illuminate\Http\Request$request *@return\Illuminate\Routing\Route * *@throws\Symfony\Component\HttpKernel\Exception\NotFoundHttpException */ publicfunctionmatch(Request$request) { //根据请求动作找到全局匹配的路由 //可以自行打印下$routes $routes=$this->get($request->getMethod()); //匹配路由下面查看框架如何生成的路由规则!!! $route=$this->matchAgainstRoutes($routes,$request); if(!is_null($route)){ return$route->bind($request); } $others=$this->checkForAlternateVerbs($request); if(count($others)>0){ return$this->getRouteForMethods($request,$others); } thrownewNotFoundHttpException; }
下面说明框架如何加载的路由规则
Application::boot方法
//主要逻辑是调用服务提供者的boot方法 array_walk($this->serviceProviders,function($p){ $this->bootProvider($p); });
App\Providers\RouteServiceProvider::boot方法
publicfunctionboot() { //调用父类Illuminate\Foundation\Support\Providers\RouteServiceProvider的boot方法 parent::boot(); }
Illuminate\Foundation\Support\Providers\RouteServiceProvider::boot方法
publicfunctionboot() { $this->setRootControllerNamespace(); if($this->routesAreCached()){ $this->loadCachedRoutes(); }else{ //就看这个loadRoutes方法 $this->loadRoutes(); $this->app->booted(function(){ //dd(get_class($this->app['router'])); $this->app['router']->getRoutes()->refreshNameLookups(); $this->app['router']->getRoutes()->refreshActionLookups(); }); } } /** *Loadtheapplicationroutes. *看注释就知道我们来对了地方 *@returnvoid */ protectedfunctionloadRoutes() { //调用App\Providers\RouteServiceProvider的map方法 if(method_exists($this,'map')){ $this->app->call([$this,'map']); } }
App\Providers\RouteServiceProvider::map方法
publicfunctionmap() { //为了调试方便我注释掉了api路由 //$this->mapApiRoutes(); //这两个都是加载路由文件这里查看web.php $this->mapWebRoutes(); } protectedfunctionmapWebRoutes() { //调用Router的__call方法返回的是RouteRegistrar实例 Route::middleware('web') ->namespace($this->namespace) //调用RouteRegistrar的namespace方法触发__call魔术方法 //依然是挂载属性可自行打印 //Illuminate\Routing\RouteRegistrar{#239▼ //#router:Illuminate\Routing\Router{#34▶} //#attributes:array:2[▼ //"middleware"=>array:1[▼ //0=>"web" //] //"namespace"=>"App\Http\Controllers" //] //#passthru:array:7[▶] //#allowedAttributes:array:7[▶] //#aliases:array:1[▶] //} //调用RouteRegistrar的group方法 ->group(base_path('routes/web.php')); }
Router::__call方法
publicfunction__call($method,$parameters) { if(static::hasMacro($method)){ return$this->macroCall($method,$parameters); } if($method==='middleware'){ //调用了RouteRegistrar的attribute方法只是挂载路由属性 return(newRouteRegistrar($this))->attribute($method,is_array($parameters[0])?$parameters[0]:$parameters); } return(newRouteRegistrar($this))->attribute($method,$parameters[0]); }
Illuminate\Routing\RouteRegistrar::__call方法
publicfunction__call($method,$parameters) { if(in_array($method,$this->passthru)){ //当使用getpost等方法的时候 return$this->registerRoute($method,...$parameters); } if(in_array($method,$this->allowedAttributes)){ if($method==='middleware'){ return$this->attribute($method,is_array($parameters[0])?$parameters[0]:$parameters); } //dd($method);//namespace return$this->attribute($method,$parameters[0]); } thrownewBadMethodCallException(sprintf( 'Method%s::%sdoesnotexist.',static::class,$method )); }
Illuminate\Routing\RouteRegistrar::group方法
publicfunctiongroup($callback) { //dd($this->attributes,$callback); //array:2[▼ //"middleware"=>array:1[▼ //0=>"web" //] //"namespace"=>"App\Http\Controllers" //] //"/home/vagrant/code/test1/routes/web.php" //查看Router的group方法 $this->router->group($this->attributes,$callback); }
Router::group方法
publicfunctiongroup(array$attributes,$routes) { $this->updateGroupStack($attributes); //查看loadRoutes方法/home/vagrant/code/test1/routes/web.php $this->loadRoutes($routes); array_pop($this->groupStack); } protectedfunctionloadRoutes($routes) { if($routesinstanceofClosure){ //用于闭包嵌套laravel的路由是可以随意潜逃组合的 $routes($this); }else{ //加载路由文件/home/vagrant/code/test1/routes/web.php (newRouteFileRegistrar($this))->register($routes); } }
Illuminate\Routing\RouteFileRegistrar文件
protected$router; publicfunction__construct(Router$router) { $this->router=$router; } publicfunctionregister($routes) { $router=$this->router; //终于加载到了路由文件 //require("/home/vagrant/code/test1/routes/web.php"); //看到这里就到了大家熟悉的Route::get()等方法了 //道友们可能已经有了有趣的想法:可以在web.php等路由文件中继续require其他文件 //便可实现不同功能模块的路由管理 require$routes; }
了解了理由加载流程,下面举个简单例子,laravel如何注册一个路由
//web.php中 Route::get('routecontroller',"\App\Http\Controllers\Debug\TestController@index"); //跳转到Router的get方法 /** *RegisteranewGETroutewiththerouter. * *@paramstring$uri *@param\Closure|array|string|callable|null$action *@return\Illuminate\Routing\Route */ publicfunctionget($uri,$action=null) { //dump($uri,$action); //$uri=routecontroller //$action=\App\Http\Controllers\Debug\TestController@index //跳转到addRoute方法 return$this->addRoute(['GET','HEAD'],$uri,$action); } /** *Addaroutetotheunderlyingroutecollection. * *@paramarray|string$methods *@paramstring$uri *@param\Closure|array|string|callable|null$action *@return\Illuminate\Routing\Route */ //['GET','HEAD'],$uri,$action publicfunctionaddRoute($methods,$uri,$action) { //routes是routecollection实例 //跳转到createRoute方法 //跳转到RouteCollection的add方法 return$this->routes->add($this->createRoute($methods,$uri,$action)); } /** *Createanewrouteinstance. * *@paramarray|string$methods *@paramstring$uri *@parammixed$action *@return\Illuminate\Routing\Route */ //['GET','HEAD'],$uri,$action protectedfunctioncreateRoute($methods,$uri,$action) { //跳转到actionReferencesController方法 if($this->actionReferencesController($action)){ $action=$this->convertToControllerAction($action); //dump($action); //array:2[▼ //"uses"=>"\App\Http\Controllers\Debug\TestController@index" //"controller"=>"\App\Http\Controllers\Debug\TestController@index" //] } //创建一个对应路由规则的Route实例并且添加到routes(collection)中 //返回到上面的addRoute方法 //请自行查看Route的构造方法 $route=$this->newRoute( //dump($this->prefix); //routecontroller $methods,$this->prefix($uri),$action ); if($this->hasGroupStack()){ $this->mergeGroupAttributesIntoRoute($route); } $this->addWhereClausesToRoute($route); return$route; } /** *Determineiftheactionisroutingtoacontroller. * *@paramarray$action *@returnbool */ //判断是否路由到一个控制器 protectedfunctionactionReferencesController($action) { //在此例子中Route::get方法传递的是一个字符串 if(!$actioninstanceofClosure){ //返回true returnis_string($action)||(isset($action['uses'])&&is_string($action['uses'])); } returnfalse; }
RouteCollection的add方法
/** *AddaRouteinstancetothecollection. * *@param\Illuminate\Routing\Route$route *@return\Illuminate\Routing\Route */ publicfunctionadd(Route$route) { //跳转吧 $this->addToCollections($route); $this->addLookups($route); //最终一路返回到Router的get方法所以我们可以直接打印web.php定义的路由规则 return$route; } /** *Addthegivenroutetothearraysofroutes. * *@param\Illuminate\Routing\Route$route *@returnvoid */ protectedfunctionaddToCollections($route) { $domainAndUri=$route->getDomain().$route->uri(); //dump($route->getDomain(),$route->uri());nullroutecontroller foreach($route->methods()as$method){ //将路由规则挂载到数组方便匹配 $this->routes[$method][$domainAndUri]=$route; } //将路由规则挂载的数组方便匹配 $this->allRoutes[$method.$domainAndUri]=$route; }
至此就生成了一条路由注意我这里将注册api路由进行了注释,并且保证web.php中只有一条路由规则
以上是路由的加载这部分是在$this->bootstrap()方法中完成的,还远没有到达路由分发和匹配的阶段,希望大家能够理解,至此路由规则生成完毕保存到了RouteCollection实例中,每个路由规则都是一个Route对象,供请求进行匹配
下面根据此条路由进行匹配,并执行返回结果
我们回到Illuminate\Routing\RouteCollection::match方法
publicfunctionmatch(Request$request) { //获取符合当前请求动作的所有路由 //是一个Route对象数组每一个对象对应一个route规则 $routes=$this->get($request->getMethod()); //匹配到当前请求路由 $route=$this->matchAgainstRoutes($routes,$request); if(!is_null($route)){ //将绑定了请求的Route实例返回 return$route->bind($request); } $others=$this->checkForAlternateVerbs($request); if(count($others)>0){ return$this->getRouteForMethods($request,$others); } thrownewNotFoundHttpException; } //该方法中大量使用了collect方法请查看laravel手册 protectedfunctionmatchAgainstRoutes(array$routes,$request,$includingMethod=true) { //dump(get_class_methods(get_class(collect($routes)))); //dump(collect($routes)->all());//items数组protected属性 //dump(collect($routes)->items);//items属性是一个数组 //当注册一个兜底路由的时候(通过Route::fallback方法)对应$route的isFallback会被设为true //partition方法根据传入的闭包将集合分成两部分 //具体实现可以查看手册集合部分 [$fallbacks,$routes]=collect($routes)->partition(function($route){ return$route->isFallback; }); //将兜底路由放到集合后面并且通过first方法找到第一个匹配的路由 return$routes->merge($fallbacks)->first(function($value)use($request,$includingMethod){ return$value->matches($request,$includingMethod); }); }
Router文件
protectedfunctionfindRoute($request) { //可以打印$route你会发现和你在web.php中打印的是同一个Route对象 $this->current=$route=$this->routes->match($request); //将匹配到的路由实例挂载到容器 $this->container->instance(Route::class,$route); return$route; } publicfunctiondispatchToRoute(Request$request) { //跳转到runRoute方法 return$this->runRoute($request,$this->findRoute($request)); } protectedfunctionrunRoute(Request$request,Route$route) { //给request帮顶当前的route可以使用$request->route()方法获取route实例 //你也可以随时在你的业务代码中通过容器获得当前Route实例 //app(Illuminate\Routing\Route::class) $request->setRouteResolver(function()use($route){ return$route; }); $this->events->dispatch(newRouteMatched($route,$request)); //开始准备响应了 return$this->prepareResponse($request, //跳转到runRouteWithinStack方法 $this->runRouteWithinStack($route,$request) ); } protectedfunctionrunRouteWithinStack(Route$route,Request$request) { $shouldSkipMiddleware=$this->container->bound('middleware.disable')&& $this->container->make('middleware.disable')===true; $middleware=$shouldSkipMiddleware?[]:$this->gatherRouteMiddleware($route); //依旧是一个pipeline我们跳转到$route->run方法 return(newPipeline($this->container)) ->send($request) ->through($middleware) ->then(function($request)use($route){ return$this->prepareResponse( $request,$route->run() ); }); }
Route::run方法注意此方法的返回值是直接从匹配的控制器或者闭包中返回的
publicfunctionrun() { $this->container=$this->container?:newContainer; try{ //如果是一个控制器路由规则 //显然我们的此条路由是一个控制器路由 if($this->isControllerAction()){ //将执行的结果返回给$route->run() //跳回到上面的prepareResponse方法 return$this->runController(); } //如果是一个闭包路由规则ControllerDispatcher return$this->runCallable(); }catch(HttpResponseException$e){ return$e->getResponse(); } } /** *Runtherouteactionandreturntheresponse. * *@returnmixed * *@throws\Symfony\Component\HttpKernel\Exception\NotFoundHttpException */ protectedfunctionrunController() { // return$this->controllerDispatcher()->dispatch( $this, //通过容器解析当前路由控制器实例 $this->getController(), //获取当前路由控制器方法 $this->getControllerMethod() ); }
Illuminate\Routing\ControllerDispatcher::dispatch方法
/** *Dispatcharequesttoagivencontrollerandmethod. * *@param\Illuminate\Routing\Route$route *@parammixed$controller *@paramstring$method *@returnmixed */ publicfunctiondispatch(Route$route,$controller,$method) { $parameters=$this->resolveClassMethodDependencies( $route->parametersWithoutNulls(),$controller,$method ); if(method_exists($controller,'callAction')){ //执行基类控制器中的callAction方法并返回执行结果 return$controller->callAction($method,$parameters); } return$controller->{$method}(...array_values($parameters)); }
控制器方法返回的结果到Router::runRouteWithinStack方法
protectedfunctionrunRouteWithinStack(Route$route,Request$request) { $shouldSkipMiddleware=$this->container->bound('middleware.disable')&& $this->container->make('middleware.disable')===true; $middleware=$shouldSkipMiddleware?[]:$this->gatherRouteMiddleware($route); return(newPipeline($this->container)) ->send($request) ->through($middleware) ->then(function($request)use($route){ return$this->prepareResponse( //返回到这里然后执行prepareResponse方法 $request,$route->run() ); }); } //实际调用的是toResponse方法 //注意这里的$response是直接从控制器中返回的任何东西 publicstaticfunctiontoResponse($request,$response) { if($responseinstanceofResponsable){ //我们当然可以直接从控制器中返回一个实现了Responsable接口的实例 $response=$response->toResponse($request); } if($responseinstanceofPsrResponseInterface){ //什么???laravel还支持psr7??当然了后面会附上使用文档 $response=(newHttpFoundationFactory)->createResponse($response); }elseif($responseinstanceofModel&&$response->wasRecentlyCreated){ //知道为什么laravel允许直接返回一个模型了吗 $response=newJsonResponse($response,201); }elseif(!$responseinstanceofSymfonyResponse&& //知道laravel为什么允许你直接返回数组了吗 ($responseinstanceofArrayable|| $responseinstanceofJsonable|| $responseinstanceofArrayObject|| $responseinstanceofJsonSerializable|| is_array($response))){ $response=newJsonResponse($response); }elseif(!$responseinstanceofSymfonyResponse){ //如果没匹配到比如response是一个字符串,null等直接生成响应类 //我们从laravel的Response构造方法开始梳理 $response=newResponse($response); } if($response->getStatusCode()===Response::HTTP_NOT_MODIFIED){ $response->setNotModified(); } return$response->prepare($request); }
首先我们来看直接生成laravel响应Illuminate\Http\Response
继承了Symfony\Component\HttpFoundation\Response
//Symfony\Component\HttpFoundation\Response publicfunction__construct($content='',int$status=200,array$headers=[]) { //可以看到基本什么都没做 $this->headers=newResponseHeaderBag($headers); //调用Illuminate\Http\Response的setContent方法设置响应内容呗 $this->setContent($content); $this->setStatusCode($status); $this->setProtocolVersion('1.0'); } //Illuminate\Http\Response::setContent publicfunctionsetContent($content) { $this->original=$content; //shouldBeJson方法将实现了特定接口的response或者是一个array的response转换为 //并设置响应头 if($this->shouldBeJson($content)){ $this->header('Content-Type','application/json'); //morphToJson方法保证最终给此响应设置的响应内容为json串 $content=$this->morphToJson($content); } elseif($contentinstanceofRenderable){ $content=$content->render(); } //Symfony\Component\HttpFoundation\Response如果最终设置的响应内容不是null或者字符串或者实现了__toString方法的类那么跑出异常,否则设置响应内容 parent::setContent($content); return$this; } //Symfony\Component\HttpFoundation\Response::setContent方法 publicfunctionsetContent($content) { if(null!==$content&&!\is_string($content)&&!is_numeric($content)&&!\is_callable([$content,'__toString'])){ //php官方建议不要使用gettype方法获取变量的类型 thrownew\UnexpectedValueException(sprintf('TheResponsecontentmustbeastringorobjectimplementing__toString(),"%s"given.',\gettype($content))); } //(string)会触发__toString方法如何对象允许的话 $this->content=(string)$content; return$this; }
拿到响应后执行return$response->prepare($request);
/** *PreparestheResponsebeforeitissenttotheclient. * *ThismethodtweakstheResponsetoensurethatitis *compliantwithRFC2616.Mostofthechangesarebasedon *theRequestthatis"associated"withthisResponse. * *@return$this */ //总的来说就是设置各种响应头注意此时并未发送响应 publicfunctionprepare(Request$request) { $headers=$this->headers; //如果是100204304系列的状态码就删除响应数据删除对应的数据头 if($this->isInformational()||$this->isEmpty()){ $this->setContent(null); $headers->remove('Content-Type'); $headers->remove('Content-Length'); }else{ //Content-typebasedontheRequest if(!$headers->has('Content-Type')){ $format=$request->getPreferredFormat(); if(null!==$format&&$mimeType=$request->getMimeType($format)){ $headers->set('Content-Type',$mimeType); } } //FixContent-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')){ //addthecharset $headers->set('Content-Type',$headers->get('Content-Type').';charset='.$charset); } //FixContent-Length if($headers->has('Transfer-Encoding')){ $headers->remove('Content-Length'); } if($request->isMethod('HEAD')){ //cf.RFC261614.13 $length=$headers->get('Content-Length'); $this->setContent(null); if($length){ $headers->set('Content-Length',$length); } } } //Fixprotocol if('HTTP/1.0'!=$request->server->get('SERVER_PROTOCOL')){ $this->setProtocolVersion('1.1'); } //Checkifweneedtosendextraexpireinfoheaders 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; } //至此我们的响应封装好了等待发送给客户端 //在发送之前还要将响应逐步返回 //值得注意的是如果你给此路由设置了后置中间件可能如下 publicfunctionhandle($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
publicfunctionsend() { //先发送响应头 $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; } publicfunctionsendHeaders() { //headershavealreadybeensentbythedeveloper if(headers_sent()){ return$this; } //headers foreach($this->headers->allPreserveCaseWithoutCookies()as$name=>$values){ $replace=0===strcasecmp($name,'Content-Type'); foreach($valuesas$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; } //发送响应内容 publicfunctionsendContent() { //想笑吗就是这么简单 echo$this->content; return$this; } //至此真的响应了客户端了
$kernel->terminate($request,$response);
Illuminate\Foundation\Http\Kernel::terminate方法
/** *Calltheterminatemethodonanyterminablemiddleware. * *@param\Illuminate\Http\Request$request *@param\Illuminate\Http\Response$response *@returnvoid */ publicfunctionterminate($request,$response) { //调用实现了terminate方法的中间件 $this->terminateMiddleware($request,$response); //执行注册的callback $this->app->terminate(); }
laravel将控制器(闭包)返回的数据封装成response对象
publicstaticfunctiontoResponse($request,$response) { if($responseinstanceofResponsable){ $response=$response->toResponse($request); } if($responseinstanceofPsrResponseInterface){ $response=(newHttpFoundationFactory)->createResponse($response); }elseif($responseinstanceofModel&&$response->wasRecentlyCreated){ $response=newJsonResponse($response,201); }elseif(!$responseinstanceofSymfonyResponse&& ($responseinstanceofArrayable|| $responseinstanceofJsonable|| $responseinstanceofArrayObject|| $responseinstanceofJsonSerializable|| is_array($response))){ $response=newJsonResponse($response); }elseif(!$responseinstanceofSymfonyResponse){ $response=newResponse($response); } if($response->getStatusCode()===Response::HTTP_NOT_MODIFIED){ $response->setNotModified(); } return$response->prepare($request); }
观察上面的代码发现:
1上面代码的作用是将路由节点返回的数据封装成Response对象等待发送
2并且上面的代码存在大量的instanceof判断(为什么要这样呢是因为一旦我们从控制器中返回一个实现了
laravel指定接口的实例,laravel就知道该如何渲染这些响应给客户端此时你可能还不清楚,请看下面的例子)
3而且没有else分支(这是因为laravel允许我们直接返回reponse对象,当我们直接返回Resposne实例的时候会直接走到方法的最后一句话)
4并且最终都调用的都是SymfonyResponse的prepare方法
我们先来看Responsable接口在laravel中任何一个实现了此接口的对象都可以响应给客户端
status=$order->status; } publicfunctiontoResponse($request) { if($this->status){ //订单以完成 returnnewJsonResponse('ordercompleted',200); } //订单未结算 returnview('needToCharge'); } } 3创建控制器看toResponse代码我们发现只要我们想办法返回符合laravel规定的数据,最终都会被转换成laravelresponse实例比如我们可以返回Responsable实例,Arrayable实例,Jsonable实例等等,大家可以尝试直接返回returnnewResponse(),Response::create等等
Route::get('rawReponse',function(){
returnnewResponse(range(1,10));
});
更多请查看这位老哥的博客
通过十篇水文,分享了从类的自动加载,到走完laravel的生命周期。
第一次写博客不足太多,不爱看大量代码的道友,可以查看这位外国老哥的博客,其代码较少,但逻辑清晰明了。发现错误,欢迎指导,感谢!!!
collection文档
laravel中使用psr7
总结
到此这篇关于LaravelReponse响应客户端的文章就介绍到这了,更多相关LaravelReponse响应客户端内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。