在laravel5.2中,Http的主要功能就是過濾Http請求(php aritsan
是沒有中間件機制的),同時也讓系統的層次(Http過濾層)更明確,使用起來也很優雅。但實現中間件的程式碼卻很複雜,下面就來具分析下有關中間件的源碼的內容。
中間件原始碼
中間件本身分為兩種,一種是所有http的,另一種則是針對route的。一個有中間件的請求週期是:Request得先經過Http中間件#,才能進行Router,再經過Requset所對應Route的Route中間件, 最後才會進入對應的Controller程式碼。 laravel把請求分為了兩種:http和console。不同的請求方式用它自己的Kernel
來驅動Application
。 Http請求則是透過\Illuminate\Foundation\Http\Kernel
類別來驅動,它定義了所有的中間件,其父類別\Illuminate\Foundation\Http\Kernel:: handle
就是對請求進行處理的入口了
Http中間件
追蹤入口handle()
方法,很容易發現該函數(\Illuminate\Foundation\Http\Kernel::sendRequestThroughRouter
):
protected function sendRequestThroughRouter($request) { $this->app->instance('request', $request); Facade::clearResolvedInstance('request'); $this->bootstrap(); return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter()); }
該函數會把Requset分發到Router(透過方法名稱就知道了), 主要的邏輯則是透過\Illuminate\Routing\Pipeline
完成的, 作用就是讓Requset通過Http中間件的偵測,然後再到達Router。這裡的程式碼看起來很優雅,但不是很好理解。所以,了解Pipeline
的運作機制就會明白中間件的使用。
Pipeline的運行實作
Pipleline
基底類別是\Illuminate\Pipeline\Pipeline
,它的執行在then
方法:
public function then(Closure $destination) { $firstSlice = $this->getInitialSlice($destination); $pipes = array_reverse($this->pipes); return call_user_func( array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable ); }
了解這段程式碼執行的意圖,必須知道array_reduce()做了什麼。為了清楚array_reduce
怎麼運作的,先把array_reduce
重寫一次:
//将数组中的元素,依次执行$func函数,且上一次的$func的返回值作为下一次调用$func的第一个参数输入 function array_reduce_back($arr, callable $func, $firstResult = null) { $result = $firstResult; foreach ($arr as $v) { $result = $func($result, $v); } return $result; }
所以,原始碼中的$func
#是getSlice()
,它回傳的是一個回呼函數:function($passable) use ($stack, $pipe){...}
($stack
和$pipe
被輸入的具體值取代),也就是說作為上一次返回結果輸入到下一次$func
的第一個參數是上述的回調函數,如此循環,當陣列遍歷完成,array_reduce
就回傳的是一個回呼函數,現在關鍵就是要了解這個回呼函數是什麼樣子,又該如何執行?為方便討論,可分析下面的程式碼:
call_user_func( array_reduce([1, 2, 3], $this->getSlice(), $firstSlice), $this->passable );
執行說明:
1.$result_0
是初始化的值,為$firstSlice
,即是\Illuminate\Pipeline\Pipeline::getInitialSlice
的回傳回呼
2.每遍歷一個元素,都會執行\Illuminate\Pipeline\Pipeline:: getSlice
的回調,同時也會傳回一個回呼
3.$result
中的具體執行程式碼都在getSlice()
中
4.最後的array_reduce
回傳結果是$result_3
,是一個有多層閉包的回呼函數
5.執行的是call_user_func($result_3, $this-> passable)
,即執行function($this->passable) use ($result_2, 3){...}
then( )是如何運作的了,要繼續下去,則需再搞定回呼函數到底怎麼執行的.現在再跟著
sendRequestThroughRouter中的
Pipeline走,看它是如何執行的。
// 把具体的参数带进来 return (new Pipeline($this->app)) ->send($request) ->through(['\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode']) ->then($this->dispatchToRouter());用上面的所分析的
Pipeline執行過程,很快就會分析出最後執行的是
function($requset) use (\Illuminate\Foundation\Http\Kernel::dispatchToRouter(), '\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode') { if ($pipe instanceof Closure) { return call_user_func($pipe, $passable, $stack); } // $name和$parameters很容易得到 // $name = '\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode'; // $parameters = []; list($name, $parameters) = $this->parsePipeString($pipe); // 执行的就是\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::handle($request, \Illuminate\Foundation\Http\Kernel::dispatchToRouter()) return call_user_func_array([$this->container->make($name), $this->method], array_merge([$passable, $stack], $parameters)); }邏輯處理已經到了
\Illuminate\ Foundation\Http\Middleware\CheckForMaintenanceMode::handle,其程式碼是:
public function handle($request, Closure $next) { if ($this->app->isDownForMaintenance()) { throw new HttpException(503); } return $next($request); }這裡,它處理了這個中間件所需過濾的條件,同時執行了
$next($request ),即
\Illuminate\Foundation\Http\Kernel::dispatchToRouter(), 這樣,就把Request轉到了Router中,也就完成了Http中間件的所有處理工作,而
$next($request)是每個中間件都不可少的操作,因為在回調中嵌套了回調,就是靠中間件把
Request傳遞到下一個回調中,也就會解析到下一個中間件,直到最後一個。緊跟著上面的已分析的
Pipeline執行過程,講其補充完整:
getSlice實例化中間件,執行其
handle,在中間件處理中執行回呼
$next( $request) ,才能確保回呼中的回呼會執行,執行的順序就是3::handel,2::handel,1::handel,$first
8.最里面一层,一定是传递给then()的参数,then执行的就是最后一步
9.执行的顺序是由数组中的最后一个,向前,到then()的参数,为了使其执行顺序是数组中的第一个到最后一个,再到then()中的参数,then()方法中就做了一个反转array_reverse
Pipeline小结
现在,Pipeline的所有执行流程就都分析完了。实现代码真的很绕,但理解之后编写自定义的中间件应该就很容易了。现在再把Pipeline
的使用翻译成汉语,应该是这样的
// 使用管道,发送$request,使之通过middleware ,再到$func (new Pipeline($this->app))->send($request)->through($this->middleware)->then($func);
这样的代码不管是从语义上,还是使用上都很优雅,高!确实是高!再回到源码,Requset的流程就通过dispatchToRouter
进入到了Router
Route中间件
在Router中,\Illuminate\Routing\Router::dispatch
就承接了来自Http中间件的Requset, Router把Request分发到了具体的Route,再进行处理,主要代码如下:
public function dispatchToRoute(Request $request) { // 找到具体的路由对象,过程略 $route = $this->findRoute($request); $request->setRouteResolver(function () use ($route) { return $route; }); // 执行Request匹配到Route的事件,具体的代码在这里:\Illuminate\Foundation\Providers\FoundationServiceProvider::configureFormRequests $this->events->fire(new Events\RouteMatched($route, $request)); // 这里就运行路由中间件了 $response = $this->runRouteWithinStack($route, $request); return $this->prepareResponse($request, $response); } protected function runRouteWithinStack(Route $route, Request $request) { // 获取该路由上的中间件 // 简单就点可这样写: // $middleware = App::shouldSkipMiddleware() ? [] : $this->gatherRouteMiddlewares($route); $shouldSkipMiddleware = $this->container->bound('middleware.disable') && $this->container->make('middleware.disable') === true; $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddlewares($route); // 了解Pipeline后,这里就好理解了,应该是通过管道,发送$request,经过$middleware,再到then中的回调 return (new Pipeline($this->container)) ->send($request) ->through($middleware) ->then(function ($request) use ($route) { return $this->prepareResponse( $request, $route->run($request) ); }); }
如何获取Route中间件的,就可以跟gatherRouteMiddlewares
,这个代码并不难,很好跟。接下来,Request就到到达至于Controller, Request是如何到达Controller的代码就不难了,这里就不说了
Controller后执行中间件
成功获取Response后,在public/index.php
58行执行了$kernel->terminate($request, $response);
, 也就是在主要逻辑处理完成之后,再执行此代码,它实际上调用是的\Illuminate\Foundation\Http\Kernel::terminate
, 跟进去就很容易发现,它处理了这此请求所涉及到的中间件,并执行了各自的terminate
方法,到这里,中间件的另一个功能就展现出来了,就是主要逻辑完成之后的收尾工作.到这里为止,中间件就完成了它的使命(一个请求也就完成了)
如何使用中间件
在官方文档上讲解的很清楚注册中间
中间件小结
至此,中间件的实现逻辑与使用就清晰了.从执行的顺序来分,一个在Controller
之前,一个在Controller
之后,所以它一个很重要的作用就是可以让Controller
专注于自己的主要逻辑的职责更明确. 奇怪的是,但前后两种中间件的执行方式却不一样, \Illuminate\Foundation\Http\Kernel::terminate
,中间件的结束却没有使用Pipeline
, 而是直接foreach
.相同的工作却用两种代码来实现.现在看来,中间件本身并不复杂,但它带给了我两个启发,1.层次明确 2,Pipeline
所带来的优雅.
相关推荐:
Laravel 5.1框架中如何创建自定义Artisan控制台命令
以上是基於laravel5.2進行中間件源碼的解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

taskManagementsToolSareEssentialForefectiverMototeprojectManagementbyPrioritizingTaskSandTrackingProgress.1)USETOOLSLIKETRELLOANDASANATASANATOSETPRIORITIONTAGS.2)

Laravel10enhancesPerformancEthroughSeveralKeyKeyFeatures.1)itintroducesquereBuilderCachingTordorcachingTordOuctedSataBaseload.2)itoptimiesseloizeseloquentmodelloAdingwithlazyproxies.3)

最佳的全棧Laravel應用部署策略包括:1.零停機部署,2.藍綠部署,3.持續部署,4.金絲雀發布。 1.零停機部署使用Envoy或Deployer自動化部署過程,確保應用在更新時保持可用。 2.藍綠部署通過維護兩個環境實現無停機部署,並允許快速回滾。 3.持續部署通過GitHubActions或GitLabCI/CD自動化整個部署流程。 4.金絲雀發布通過Nginx配置,將新版本逐步推廣給用戶,確保性能優化和快速回滾。

toscalealaravelApplication有效,焦點databaseSharding,緩存,負載平衡和microservices.1)實現DataBasEshardingTodistaCripedataCrossmultipledataBasesForimProvesforimPrevperformance.2)uselaravel'scachingsystemystemystemystemywithredsormememememememcachedtebachedtebab

doovercomecommunicationbarriersIndistributedTeams,使用:1)VideoCallSforface-to-Faceinteraction,2)setClearresponsEtimepections,3)chooseappropropropraproproprapropropriatecommunicationTools,4)CreatseateAteAteAteamCommunicationGuide和5)建立PemersonalBoundariestAriestOpeopReventBreventBurniationBurnication.the

laravelbladeenhancesfrontendtemplatinginflatinginflationll-stackprojectsbyferingCleanSyntaxandaxandpoperfelfulfeatures.1)itallowsforeasyvariableasyvariabledisplayandControlstructures.2)bladesuportsuportsuportscreatingingingingingingingingingingangingandredreingscomponents components components components,aidinginmanagingcomplexuis.3)

laravelisidealforll-stackapplicationsduetoitselegantsyntax,complastissionecosystem和perperatedfulfeatures.1)useeloquentormforintuivelbackenddatamanipulation,butavoidn 1queryissues.2)

forremotework,iusezoomforvideOcalls,Slackformessing,trelloforprojectmanagement,and giThubForCodeCollaboration.1)Zoomisreliable forlailible forlargemeetingsbuthastimelimitsonthefreeversion.2)


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SublimeText3漢化版
中文版,非常好用

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

Dreamweaver CS6
視覺化網頁開發工具

Dreamweaver Mac版
視覺化網頁開發工具

SublimeText3 Linux新版
SublimeText3 Linux最新版