Laravel中使用uploadify 上传文件返回出现debugbar信息解决思路
Laravel中使用uploadify 上传文件返回出现debugbar信息解决思路
Laravel5.5源码详解 – Laravel-debugbar 及使用elementUI - ajax的注意事项
关于laravel对中间件的处理,请参中间件考另文,
Laravel5.5源码详解 – 中间件MiddleWare分析
这里只是快速把debugbar的事务处理流程记录一遍。
我在Illuminate\Pipeline\Pipeline的then函数中进行中间件捕获,发现有下面这些中间件,
array:6 [▼0 => Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode1 => Illuminate\Foundation\Http\Middleware\ValidatePostSize2 => App\Http\Middleware\TrimStrings => Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToull4 => App\Http\Middleware\TrustProxies5 => Barryvdh\Debugbar\Middleware\InjectDebugbar
]
array:6 [▼0 => App\Http\Middleware\EncryptCookies1 => Illuminate\Cookie\Middleware\AddQueuedCookiesToRespe2 => Illuminate\Session\Middleware\StartSession => Illuminate\View\Middleware\ShareErrorsFromSession4 => App\Http\Middleware\VerifyCsrfToken5 => Illuminate\Routing\Middleware\SubstituteBindings
]
其中就包括这个Barryvdh\Debugbar\Middleware\InjectDebugbar
,它是在larave启动时,在vendor\composer\installed.json
发现并引入,
laravel-debugbar的配置在Barryvdh\laravel-debugbar\config\debugbar
,里面解释比较详尽,这里也不再重复。顺便说一下,这个类是在Barryvdh\Debugbar\ServiceProvider
中注册的,
<?php namespace Barryvdh\Debugbar;use Barryvdh\Debugbar\Middleware\DebugbarEnabled;
use Barryvdh\Debugbar\Middleware\InjectDebugbar;
use DebugBar\DataFormatter\DataFormatter;
use DebugBar\DataFormatter\DataFormatterInterface;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Routing\Router;
use Illuminate\Session\SessionManager;class ServiceProvider extends \Illuminate\Support\ServiceProvider
{protected $defer = false;public function register(){$configPath = __DIR__ . /../config/debugbar.php ;$this->mergeConfigFrom($configPath, debugbar );$this->app->alias(DataFormatter::class,DataFormatterInterface::class);$this->app->singleton(LaravelDebugbar::class, function () {$debugbar = new LaravelDebugbar($this->app);if ($this->app->bound(SessionManager::class)) {$sessionManager = $this->app->make(SessionManager::class);$httpDriver = new SymfonyHttpDriver($sessionManager);$debugbar->setHttpDriver($httpDriver);}return $debugbar;});$this->app->alias(LaravelDebugbar::class, debugbar );$this->app->singleton( command. ,function ($app) {return new Cole\ClearCommand($app[ debugbar ]);});$this->commands([ command. ]);}// 这里注册了很多事件处理功能,都是后面在处理request的时候可能会用到的public function boot(){$configPath = __DIR__ . /../config/debugbar.php ;$this->publishes([$configPath => $this->getConfigPath()], config );$routeConfig = [ namespace => Barryvdh\Debugbar\Controllers , prefix => $this->app[ config ]->get( debugbar.route_prefix ), domain => $this->app[ config ]->get( debugbar.route_domain ), middleware => [DebugbarEnabled::class],];$this->getRouter()->group($routeConfig, function($router) {$router->get( open , [ uses => OpenHandlerController@handle , as => ,]);$router->get( clockwork/{id} , [ uses => OpenHandlerController@clockwork , as => ,]);$router->get( assets/stylesheets , [ uses => AssetController@css , as => debugbar. ,]);$router->get( assets/javascript , [ uses => AssetController@js , as => debugbar.assets.js ,]);});$this->registerMiddleware(InjectDebugbar::class);}protected function getRouter(){return $this->app[ router ];}protected function getConfigPath(){return config_path( debugbar.php );}protected function publishConfig($configPath){$this->publishes([$configPath => config_path( debugbar.php )], config );}protected function registerMiddleware($middleware){$kernel = $this->app[Kernel::class];$kernel->pushMiddleware($middleware);}public function provides(){return [ debugbar , command. , DataFormatterInterface::class, LaravelDebugbar::class];}
}
重点在这里,实际处理respe和request的handle函数在Barryvdh\Debugbar\Middleware\InjectDebugbar中,
<?php namespace Barryvdh\Debugbar\Middleware;use Error;
use Closure;
use Exception;
use Illuminate\Http\Request;
use Barryvdh\Debugbar\LaravelDebugbar;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Symfony\Component\Debug\Exception\FatalThrowableError;class InjectDebugbar
{protected $container; protected $debugbar;protected $except = [];public function __ctruct(Container $container, LaravelDebugbar $debugbar){$this->container = $container;$this->debugbar = $debugbar;$this->except = config( ) ?: [];}public function handle($request, Closure $next){// 如果debugbar没有使能,或传入的request是空的,则直接返回。if (!$this->debugbar->isEnabled() || $this->inExceptArray($request)) {return $next($request);}// 注册事务处理功能$this->debugbar->boot();try {/** @var \Illuminate\Http\Respe $respe */// 可以看到,handle是处理后置的,也就是在(来回两次经过handle)回途中处理函数,// 所以这里先$next()$respe = $next($request);} catch (Exception $e) {$respe = $this->handleException($request, $e);} catch (Error $error) {$e = new FatalThrowableError($error);$respe = $this->handleException($request, $e);}// 处理后置,接上面的next()之后才是debugbar干活的时间// Modify the respe to add the Debugbar$this->debugbar->modifyRespe($request, $respe);// 处理完毕,返回结果return $respe;}
上面这段,真正起作用的就是这句:
$this->debugbar->modifyRespe($request, $respe);
,它是debugbar 修改respe的地方所在,具体请看在Barryvdh\Debugbar\LaravelDebugbar,请注意其中的注释,
public function modifyRespe(Request $request, Respe $respe)
{// 如果没有使能,就直接返回respe$app = $this->app;if (!$this->isEnabled() || $this->isDebugbarRequest()) {return $respe;}// Show the Http Respe Exception in the Debugbar, when available// 如果有Http异常,则打印显示出来if (isset($respe->exception)) {$this->addThrowable($respe->exception);}// 要不要调试设置信息,默认是不需要的if ($this->shouldCollect( config , false)) {try {$configCollector = new ConfigCollector();$configCollector->setData($app[ config ]->all());$this->addCollector($configCollector);} catch (\Exception $e) {$this->addThrowable(new Exception( Cannot add ConfigCollector to Laravel Debugbar: . $e->getMessage(),$e->getCode(),$e));}}// 如果绑定session调试if ($this->app->bound(SessionManager::class)){/** @var \Illuminate\Session\SessionManager $sessionManager */$sessionManager = $app->make(SessionManager::class);$httpDriver = new SymfonyHttpDriver($sessionManager, $respe);$this->setHttpDriver($httpDriver);if ($this->shouldCollect( session ) && ! $this->hasCollector( session )) {try {$this->addCollector(new SessionCollector($sessionManager));} catch (\Exception $e) {$this->addThrowable(new Exception( Cannot add SessionCollector to Laravel Debugbar: . $e->getMessage(),$e->getCode(),$e));}}} else {$sessionManager = null;}// 貌似这句的意思是,如果只调试一个session? 还没进入源码深究。if ($this->shouldCollect( symfony_request , true) && !$this->hasCollector( request )) {try {$this->addCollector(new RequestCollector($request, $respe, $sessionManager));} catch (\Exception $e) {$this->addThrowable(new Exception( Cannot add SymfonyRequestCollector to Laravel Debugbar: . $e->getMessage(),$e->getCode(),$e));}}// 如果要支持Clockwork调试,(比如支持Chrome插件Clockwork调试)if ($app[ config ]->get( ) && ! $this->hasCollector( clockwork )) {try {$this->addCollector(new ClockworkCollector($request, $respe, $sessionManager));} catch (\Exception $e) {$this->addThrowable(new Exception( Cannot add ClockworkCollector to Laravel Debugbar: . $e->getMessage(),$e->getCode(),$e));}$this->addClockworkHeaders($respe);}// 首先判断一下,这是不是一个redirect()的请求(刷新页面)// 这个判断的语句原型是$this->statusCode >= 00 && $this->statusCode < 400;// 函数原型在vendor\symfony\http-foundation\Respe.php中,if ($respe->isRedirection()) {try {$this->stackData();} catch (\Exception $e) {$app[ log ]->error( Debugbar exception: . $e->getMessage());}} elseif (// 如果是ajax请求,并且已经设置了对ajax进行调试,则这在里处理$this->isJsonRequest($request) &&$app[ config ]->get( _ajax , true)) {try {$this->sendDataInHeaders(true);if ($app[ config ]->get( debugbar.add_ajax_timing , false)) {$this->addServerTimingHeaders($respe);}} catch (\Exception $e) {$app[ log ]->error( Debugbar exception: . $e->getMessage());}} elseif (// 如果headers有Content-Type这个标签,并且不是html,那么就应该是JSO数据// 很明显,这里只对Content-Type=JSO的数据进行操作,// 对其他类型的数据,如图片,MSWORD等,则直接抛出异常($respe->headers->has( Content-Type ) &&strpos($respe->headers->get( Content-Type ), html ) === false)|| $request->getRequestFormat() !== html || $respe->getContent() === false) {try {// Just collect store data, don t inject it.$this->collect();} catch (\Exception $e) {$app[ log ]->error( Debugbar exception: . $e->getMessage());}} elseif ($app[ config ]->get( debugbar.inject , true)) {// 对普通的情况,debugbar会在这里修改的respe,并注入渲染try {$this->injectDebugbar($respe);} catch (\Exception $e) {$app[ log ]->error( Debugbar exception: . $e->getMessage());}}return $respe;}用到的 $app[ config ] 的原貌是这样的,Repository {#24 ▼#items: array:1 [▼app => array:1 [▶]auth => array:4 [▶]broadcasting => array:2 [▶]cache => array: [▶]database => array:4 [▶]filesystems => array: [▶]mail => array:9 [▶]queue => array: [▶]services => array:4 [▶]session => array:15 [▶]view => array:2 [▶]debugbar => array:1 [▼enabled => nullexcept => []storage => array:5 [▶]include_vendors => truecapture_ajax => trueadd_ajax_timing => falseerror_handler => falseclockwork => falsecollectors => array:21 [▶]opti => array:7 [▶]inject => trueroute_prefix => _debugbarroute_domain => null]trustedproxy => array:2 [▶]]
}
比如,这个inject是true,就对应了上面的普通调试情况,现在来到下一步的重点,
public function injectDebugbar(Respe $respe){$content = $respe->getContent();$renderer = $this->getJavascriptRenderer();if ($this->getStorage()) {$openHandlerUrl = route( );$renderer->setOpenHandlerUrl($openHandlerUrl);}$renderedContent = $renderer->renderHead() . $renderer->render();$pos = strripos($content, </body> );if (false !== $pos) {$content = substr($content, 0, $pos) . $renderedContent . substr($content, $pos);} else {$content = $content . $renderedContent;}// Update the new content and reset the content length// 在这里注入页面渲染与调试信息$respe->setContent($content); $respe->headers->remove( Content-Length );}
整个大致流程就是这样子的。
我使用的laravelvuejselementUI做练习,发现在使用elementUI时,el-upload默认并没有支持ajax,虽然它采用了XMLHttpRequest()来处理上传,但头文件并没有XHR处理,所以laravel收到其发出的只是一个普通的post请求,这种情况下,laravel-debugbar会把所有的调试信息和相关渲染,全部加入到respe中返回(对axios也是同样如此),而这恰恰不是我们所需要的,所以有必要特别细说一下。
如果是ajax请求,debugbar会在这里判断
protected function isJsonRequest(Request $request){// If XmlHttpRequest, return trueif ($request->isXmlHttpRequest()) {return true;}// Check if the request wants Json$acceptable = $request->getAcceptableContentTypes();return (isset($acceptable[0]) && $acceptable[0] == application/json );}
其中有对request是否为ajax的判断 $request->isXmlHttpRequest()
,它实际是在vendor\symfony\http-foundation\Request.php
里面,
public function isXmlHttpRequest()
{return XMLHttpRequest == $this->headers->get( X-Requested-With );
}
所以不难明白,为什么在headers里面,必须加入 X-Requested-With : XMLHttpRequest
这一行,或者是这样,
其目的就是让laravel-debugger知道,发送的是ajax请求,不要再把调试信息和页面渲染再注入respe了。
如果不加这一行的话,laravel会默认这是一个普通的Post请求,此时,larave-debugbar这样的插件,就会对respe进行注入渲染,最后这些注入的代码会返回给页面,造成混乱和难以处理。
PS:
经过上面思路,知道uploadify 上传文件后返回的信息为什么会多了debug,所以可以在php上传方法中临时关闭debugbar,代码如下:
\Debugbar::disable();
以上内容参考来源:
#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
上一篇:中国风游戏音乐的特点
下一篇:深入理解SSL VPN
推荐阅读
留言与评论(共有 17 条评论) |
本站网友 广州美食网 | 20分钟前 发表 |
$pos) . $renderedContent . substr($content | |
本站网友 大连船舶 | 28分钟前 发表 |
config );$routeConfig = [ namespace => Barryvdh\Debugbar\Controllers | |
本站网友 大概八点二十发 | 24分钟前 发表 |
7 [▶]inject => trueroute_prefix => _debugbarroute_domain => null]trustedproxy => array | |
本站网友 南京紫峰大厦 | 5分钟前 发表 |
true) && !$this->hasCollector( request )) {try {$this->addCollector(new RequestCollector($request | |
本站网友 柳州房产 | 14分钟前 发表 |
2 [▶]cache => array | |
本站网友 新华二手房 | 29分钟前 发表 |
];$this->getRouter()->group($routeConfig | |
本站网友 佛山行通济 | 30分钟前 发表 |
. $e->getMessage());}} elseif (// 如果是ajax请求,并且已经设置了对ajax进行调试,则这在里处理$this->isJsonRequest($request) &&$app[ config ]->get( _ajax | |
本站网友 两横三纵城市化战略 | 22分钟前 发表 |
$e->getCode() | |
本站网友 临淄楼市 | 16分钟前 发表 |
[ uses => AssetController@js | |
本站网友 八月洞庭秋 | 28分钟前 发表 |
LaravelDebugbar | |
本站网友 厉害的意思 | 14分钟前 发表 |
$e->getCode() | |
本站网友 硬件加速 | 9分钟前 发表 |
XMLHttpRequest 这一行,或者是这样, opti.headers[ X-Requested-With ] = XMLHttpRequest ; 其目的就是让laravel-debugger知道,发送的是ajax请求,不要再把调试信息和页面渲染再注入respe了 | |
本站网友 登高望远海 | 22分钟前 发表 |
1 [▼app => array | |
本站网友 心急如焚 | 3分钟前 发表 |
]);$router->get( assets/stylesheets | |
本站网友 流水的女人 | 0秒前 发表 |
代码如下 | |
本站网友 众品网 | 2分钟前 发表 |
class |