日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Laravel5.5源码详解 -- Laravel-debugbar及使用elementUI-ajax的注意事项

發(fā)布時間:2024/3/26 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Laravel5.5源码详解 -- Laravel-debugbar及使用elementUI-ajax的注意事项 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Laravel5.5源碼詳解 – Laravel-debugbar 及使用elementUI - ajax的注意事項(xiàng)

關(guān)于laravel對中間件的處理,請參中間件考另文,
Laravel5.5源碼詳解 – 中間件MiddleWare分析
這里只是快速把debugbar的事務(wù)處理流程記錄一遍。

我在Illuminate\Pipeline\Pipeline的then函數(shù)中進(jìn)行中間件捕獲,發(fā)現(xiàn)有下面這些中間件,

array:6 [▼0 => "Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode"1 => "Illuminate\Foundation\Http\Middleware\ValidatePostSize"2 => "App\Http\Middleware\TrimStrings"3 => "Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull"4 => "App\Http\Middleware\TrustProxies"5 => "Barryvdh\Debugbar\Middleware\InjectDebugbar" ] array:6 [▼0 => "App\Http\Middleware\EncryptCookies"1 => "Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse"2 => "Illuminate\Session\Middleware\StartSession"3 => "Illuminate\View\Middleware\ShareErrorsFromSession"4 => "App\Http\Middleware\VerifyCsrfToken"5 => "Illuminate\Routing\Middleware\SubstituteBindings" ]

其中就包括這個Barryvdh\Debugbar\Middleware\InjectDebugbar,它是在larave啟動時,在vendor\composer\installed.json發(fā)現(xiàn)并引入,

laravel-debugbar的配置在Barryvdh\laravel-debugbar\config\debugbar,里面解釋比較詳盡,這里也不再重復(fù)。順便說一下,這個類是在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.debugbar.clear',function ($app) {return new Console\ClearCommand($app['debugbar']);});$this->commands(['command.debugbar.clear']);}// 這里注冊了很多事件處理功能,都是后面在處理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' => 'debugbar.openhandler',]);$router->get('clockwork/{id}', ['uses' => 'OpenHandlerController@clockwork','as' => 'debugbar.clockwork',]);$router->get('assets/stylesheets', ['uses' => 'AssetController@css','as' => 'debugbar.assets.css',]);$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.debugbar.clear', DataFormatterInterface::class, LaravelDebugbar::class];} }

重點(diǎn)在這里,實(shí)際處理response和request的handle函數(shù)在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 __construct(Container $container, LaravelDebugbar $debugbar){$this->container = $container;$this->debugbar = $debugbar;$this->except = config('debugbar.except') ?: [];}public function handle($request, Closure $next){// 如果debugbar沒有使能,或傳入的request是空的,則直接返回。if (!$this->debugbar->isEnabled() || $this->inExceptArray($request)) {return $next($request);}// 注冊事務(wù)處理功能$this->debugbar->boot();try {/** @var \Illuminate\Http\Response $response */// 可以看到,handle是處理后置的,也就是在(來回兩次經(jīng)過handle)回途中處理函數(shù),// 所以這里先$next()$response = $next($request);} catch (Exception $e) {$response = $this->handleException($request, $e);} catch (Error $error) {$e = new FatalThrowableError($error);$response = $this->handleException($request, $e);}// 處理后置,接上面的next()之后才是debugbar干活的時間// Modify the response to add the Debugbar$this->debugbar->modifyResponse($request, $response);// 處理完畢,返回結(jié)果return $response;}

上面這段,真正起作用的就是這句:$this->debugbar->modifyResponse($request, $response); ,它是debugbar 修改response的地方所在,具體請看在Barryvdh\Debugbar\LaravelDebugbar,請注意其中的注釋,

public function modifyResponse(Request $request, Response $response) {// 如果沒有使能,就直接返回response$app = $this->app;if (!$this->isEnabled() || $this->isDebugbarRequest()) {return $response;}// Show the Http Response Exception in the Debugbar, when available// 如果有Http異常,則打印顯示出來if (isset($response->exception)) {$this->addThrowable($response->exception);}// 要不要調(diào)試設(shè)置信息,默認(rèn)是不需要的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調(diào)試if ($this->app->bound(SessionManager::class)){/** @var \Illuminate\Session\SessionManager $sessionManager */$sessionManager = $app->make(SessionManager::class);$httpDriver = new SymfonyHttpDriver($sessionManager, $response);$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;}// 貌似這句的意思是,如果只調(diào)試一個session? 還沒進(jìn)入源碼深究。if ($this->shouldCollect('symfony_request', true) && !$this->hasCollector('request')) {try {$this->addCollector(new RequestCollector($request, $response, $sessionManager));} catch (\Exception $e) {$this->addThrowable(new Exception('Cannot add SymfonyRequestCollector to Laravel Debugbar: ' . $e->getMessage(),$e->getCode(),$e));}}// 如果要支持Clockwork調(diào)試,(比如支持Chrome插件Clockwork調(diào)試)if ($app['config']->get('debugbar.clockwork') && ! $this->hasCollector('clockwork')) {try {$this->addCollector(new ClockworkCollector($request, $response, $sessionManager));} catch (\Exception $e) {$this->addThrowable(new Exception('Cannot add ClockworkCollector to Laravel Debugbar: ' . $e->getMessage(),$e->getCode(),$e));}$this->addClockworkHeaders($response);}// 首先判斷一下,這是不是一個redirect()的請求(刷新頁面)// 這個判斷的語句原型是$this->statusCode >= 300 && $this->statusCode < 400;// 函數(shù)原型在vendor\symfony\http-foundation\Response.php中,if ($response->isRedirection()) {try {$this->stackData();} catch (\Exception $e) {$app['log']->error('Debugbar exception: ' . $e->getMessage());}} elseif (// 如果是ajax請求,并且已經(jīng)設(shè)置了對ajax進(jìn)行調(diào)試,則這在里處理$this->isJsonRequest($request) &&$app['config']->get('debugbar.capture_ajax', true)) {try {$this->sendDataInHeaders(true);if ($app['config']->get('debugbar.add_ajax_timing', false)) {$this->addServerTimingHeaders($response);}} catch (\Exception $e) {$app['log']->error('Debugbar exception: ' . $e->getMessage());}} elseif (// 如果headers有Content-Type這個標(biāo)簽,并且不是html,那么就應(yīng)該是JSON數(shù)據(jù)// 很明顯,這里只對Content-Type=JSON的數(shù)據(jù)進(jìn)行操作,// 對其他類型的數(shù)據(jù),如圖片,MSWORD等,則直接拋出異常($response->headers->has('Content-Type') &&strpos($response->headers->get('Content-Type'), 'html') === false)|| $request->getRequestFormat() !== 'html'|| $response->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會在這里修改的response,并注入渲染try {$this->injectDebugbar($response);} catch (\Exception $e) {$app['log']->error('Debugbar exception: ' . $e->getMessage());}}return $response;}

用到的 $app['config'] 的原貌是這樣的,

Repository {#24 ▼#items: array:13 [▼"app" => array:13 [?]"auth" => array:4 [?]"broadcasting" => array:2 [?]"cache" => array:3 [?]"database" => array:4 [?]"filesystems" => array:3 [?]"mail" => array:9 [?]"queue" => array:3 [?]"services" => array:4 [?]"session" => array:15 [?]"view" => array:2 [?]"debugbar" => array:13 [▼"enabled" => null"except" => []"storage" => array:5 [?]"include_vendors" => true"capture_ajax" => true"add_ajax_timing" => false"error_handler" => false"clockwork" => false"collectors" => array:21 [?]"options" => array:7 [?]"inject" => true"route_prefix" => "_debugbar""route_domain" => null]"trustedproxy" => array:2 [?]] }

比如,這個inject是true,就對應(yīng)了上面的普通調(diào)試情況,現(xiàn)在來到下一步的重點(diǎn),

public function injectDebugbar(Response $response){$content = $response->getContent();$renderer = $this->getJavascriptRenderer();if ($this->getStorage()) {$openHandlerUrl = route('debugbar.openhandler');$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// 在這里注入頁面渲染與調(diào)試信息$response->setContent($content); $response->headers->remove('Content-Length');}

整個大致流程就是這樣子的。

我使用的laravel+vuejs+elementUI做練習(xí),發(fā)現(xiàn)在使用elementUI時,el-upload默認(rèn)并沒有支持ajax,雖然它采用了XMLHttpRequest()來處理上傳,但頭文件并沒有XHR處理,所以laravel收到其發(fā)出的只是一個普通的post請求,這種情況下,laravel-debugbar會把所有的調(diào)試信息和相關(guān)渲染,全部加入到response中返回(對axios也是同樣如此),而這恰恰不是我們所需要的,所以有必要特別細(xì)說一下。

如果是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() ,它實(shí)際是在vendor\symfony\http-foundation\Request.php里面,

public function isXmlHttpRequest() {return 'XMLHttpRequest' == $this->headers->get('X-Requested-With'); }

所以不難明白,為什么在headers里面,必須加入'X-Requested-With': 'XMLHttpRequest' 這一行,或者是這樣,

options.headers['X-Requested-With'] = 'XMLHttpRequest';

其目的就是讓laravel-debugger知道,發(fā)送的是ajax請求,不要再把調(diào)試信息和頁面渲染再注入response了。

如果不加這一行的話,laravel會默認(rèn)這是一個普通的Post請求,此時,larave-debugbar這樣的插件,就會對response進(jìn)行注入渲染,最后這些注入的代碼會返回給頁面,造成混亂和難以處理。

總結(jié)

以上是生活随笔為你收集整理的Laravel5.5源码详解 -- Laravel-debugbar及使用elementUI-ajax的注意事项的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。