天天看點

雲客Drupal源碼分析之HttpKernel堆棧

HttpKernel為何物?從名字可以看出它就是處理http請求的核心,隻需要把請求對象傳給它,就傳回響應對象,一次http通路大體上就算完成了(為什麼說是大體上,在實際應用中發送完響應還會做一些類似于析構函數工作的事情),為規範統一HttpKernel的使用symfony為此定義了HttpKernel接口,位于\vendor\symfony\http-kernel\HttpKernelInterface,在drupal8中所有HttpKernel定義類都必須要實作該接口,在Druapl8中HttpKernel對象并不隻有一個,而是有多個,儲存于堆棧裡,從上到下依次執行,優先級高的位于堆棧上層,從頂層開始執行,上層調用下層,形成一個類似鍊式結構的處理過程,直到有響應對象産生即終止,下層的HttpKernel可能不被執行,下面詳細講一講這個過程:

先說一說這個HttpKernel堆棧是怎麼産生的:

在drupal8中把堆棧裡面的HttpKernel對象稱之為http_middleware(http中間件),堆棧于服務容器編譯階段确定(容器在Drupal\Core\DrupalKernel中形成),對此堆棧的編譯過程定義在\core\lib\Drupal\Core\DependencyInjection\Compiler\StackedKernelPass.php,在編譯容器的時候這個CompilerPass收集所有被标記為http_middleware的服務(這樣的服務必須實作HttpKernelInterface接口),并依據優先級進行排序,将最高優先級的HttpKernel和這個排好序的數組分别作為堆棧管理對象StackedHttpKernel的第一和第二個參數,在容器中$container->get('http_kernel')取出http_kernel服務的時候取出的就是這個堆棧管理對象了,這裡順便提一下如何定義堆棧中的HttpKernel服務,該服務必須實作HttpKernel接口,并标記為http_middleware,額外可以設定priority(優先級,沒有設定預設為0)、responder(響應器,能産生響應對象時設定為真),比如頁面緩存HttpKernel服務的定義如下:

services:
  http_middleware.page_cache:
    class: Drupal\page_cache\StackMiddleware\PageCache
    arguments: ['@cache.render', '@page_cache_request_policy', '@page_cache_response_policy']
    tags:
      - { name: http_middleware, priority: 200, responder: true }
           

堆棧裡面的HttpKernel對象不一定會産生響應,它可能隻是幫助設定一下請求對象,也可能進行一些功能,請求對象會依次從高層傳遞到低層。此外使用者也可以在自己的子產品中定義HttpKernel對象,高優先級的HttpKernel可以中斷較低優先級HttpKernel的執行。

下面我們看一看預設的drupal8安裝後堆棧裡都有哪些處理核心,為便于了解我畫了一張示意圖:

雲客Drupal源碼分析之HttpKernel堆棧

初始安裝的Drupal8預設有7個處理核心,依據優先級,它們在堆棧中形成7個層,越上層優先級越高,由上往下依次執行HttpKernel的handle()方法,這些HttpKernel可選擇的實作TerminableInterface接口,如果實作,它們的terminate()方法也是從上到下依次執行,整個堆棧的實作可以看一看StackedHttpKernel類的實作,位于\vendor\stack\builder\src\Stack\StackedHttpKernel.php,下面分别看一看這7個HttpKernel都幹了什麼:

1:http_middleware.negotiation( Drupal\Core\StackMiddleware\NegotiationMiddleware)

用于進行内容協商,它會在請求對象裡面設定請求的格式,然後調用下一層的handle()方法是它的責任

2:http_middleware.reverse_proxy(Drupal\Core\StackMiddleware\ReverseProxyMiddleware)

為請求對象注入反向代理資料,該資料可以定義在站點配置檔案settings.php中

3:ban.middleware(Drupal\ban\BanMiddleware)

它就是管理背景/擴充子產品裡面的Ban子產品,它查詢資料庫獲得不允許通路站點的IP,如果是禁止的ip則終斷下層HttpKernel的處理,給出内容為拒絕通路的響應對象,如果你想快速學習子產品開發,那麼核心的Ban子產品是很好的教程,裡面有服務定義、權限定義、菜單定義、表單定義、資料庫操作、路由定義等等,它可以成為你借鑒的第一個子產品開發案例

4:http_middleware.page_cache(Drupal\page_cache\StackMiddleware\PageCache)

緩存層,根據請求對象查找是否有緩存的資料,有則直接産生響應,否則繼續下層的處理,并把可緩存的響應緩存起來供以後使用,它其實就是管理背景/擴充子產品裡面的Internal Page Cache子產品,預設是不能關閉的

5:http_middleware.kernel_pre_handle(Drupal\Core\StackMiddleware\KernelPreHandle)

對請求進行預處理,你也許已經研讀過DrupalKernel類的代碼了,當時可能你疑惑裡面的preHandle方法是什麼時候調用的,沒錯,就是這個HttpKernel層的工作,它加載\core\includes裡面的許多函數庫、加載子產品函數庫、注冊流包裝器、建立請求堆棧等等,這個層僅僅為下層的處理進行許多準備工作

6:http_middleware.session(Drupal\Core\StackMiddleware\Session)

session系統就是這個時候啟動的,并将session對象注入了主請求對象中,便于後續使用

7:http_kernel.basic( Symfony\Component\HttpKernel\HttpKernel)

啟動 Symfony的HttpKernel,開始進行最裡層的請求轉為響應過程,精彩還在繼續

好了,這就是HttpKernel堆棧的結構和流程原理,它是自服務容器以來的又一大步

by:雲客【雲遊天下,做客四方】

我是雲客,【雲遊天下,做客四方】,聯系方式見首頁,歡迎轉載,但須注明出處

繼續閱讀