1. 程式人生 > 其它 >入門3請求處理

入門3請求處理

執行機制概述

每一次 Yii 應用開始處理 HTTP 請求時,它都會進行一個近似的流程。

  1. 使用者提交指向入口指令碼web/index.php的請求。
  2. 入口指令碼會載入配置陣列並建立一個應用例項用於處理該請求。
  3. 應用會通過request(請求)應用元件 解析被請求的路由
  4. 應用建立一個controller(控制器)例項具體處理請求。
  5. 控制器會建立一個action(動作)例項併為該動作執行相關的 Filters(訪問過濾器)。
  6. 如果任何一個過濾器驗證失敗,該動作會被取消。
  7. 如果全部的過濾器都通過,該動作就會被執行。
  8. 動作會載入一個數據模型,一般是從資料庫中載入。
  9. 動作會渲染一個 View(檢視),併為其提供所需的資料模型。
  10. 渲染得到的結果會返回給response(響應)應用元件。
  11. 響應元件會把渲染結果發回給使用者的瀏覽器。

下面的示意圖展示了應用是如何處理一個請求的。

啟動引導(Bootstrapping)

啟動引導是指:在應用開始解析並處理新接受請求之前,一個預先準備環境的過程。 啟動引導會在兩個地方具體進行:入口指令碼(Entry Script)應用主體(application)

入口指令碼裡,需註冊各個類庫的類檔案自動載入器(Class Autoloader,簡稱自動載入器)。 這主要包括通過其autoload.php檔案載入的Composer 自動載入器,以及通過Yii類載入的 Yii 自動載入器。之後, 入口指令碼會載入應用的

配置(configuration)並建立一個應用主體的例項。

在應用主體的建構函式中,會執行以下引導工作:

  1. 呼叫preInit()(預初始化)方法,配置一些高優先順序的應用屬性, 比如basePath屬性。
  2. 註冊錯誤處理器(ErrorHandler)
  3. 通過給定的應用配置初始化應用的各屬性。
  4. 通過呼叫init()(初始化)方法,它會順次呼叫bootstrap()從而執行引導元件。

因為引導工作必須在處理每一次請求之前都進行一遍,因此讓該過程儘可能輕量化就異常重要, 請儘可能地優化這一步驟。

請儘量不要註冊太多引導元件。只有他需要在 HTTP 請求處理的全部生命週期中都作用時才需要使用它。 舉一個用到它的範例:一個模組需要註冊額外的 URL 解析規則,就應該把它列在應用的bootstrap 屬性之中, 這樣該 URL 解析規則才能在解析請求之前生效。(譯註:換言之,為了效能需要,除了 URL 解析等少量操作之外,絕大多陣列件都應該按需載入,而不是都放在引導過程中。)

在生產環境中,可以開啟位元組碼快取,比如 APC, 來進一步最小化載入和解析 PHP 檔案所需的時間。

一些大型應用都包含有非常複雜的應用配置, 它們會被分割到許多更小的配置檔案中。 此時,可以考慮將整個配置陣列快取起來, 並在入口指令碼建立應用例項之前直接從快取中載入。

路由

入口指令碼在呼叫run()方法時,它進行的第一個操作就是解析輸入的請求,然後例項化對應的控制器動作處理這個請求。 該過程就被稱為引導路由(routing。 路由相反的操作會將給定的路由和引數生成一個可訪問的URL地址, 這個操作叫做建立URL。 創建出來的URL被請求的時候,路由處理器可以解析成原始的路由資訊和引數。

負責路由解析和建立URL的元件是URL管理器, URL管理器在程式元件中被註冊成urlManagerURL管理器提供方法parseRequest()來 解析請求的URL並返回路由資訊和引數, 方法createUrl()用來根據提供的路由和引數建立一個可訪問的URL。

在程式配置中配置urlManager元件,可以讓你的應用不改變現有程式碼的情況下 識別任意的URL格式。

請求

一個應用的請求是用yii\web\Request物件來表示的,該物件提供了諸如 請求引數(譯者注:通常是GET引數或者POST引數)、HTTP頭、cookies等資訊。 預設情況下,對於一個給定的請求,你可以通過requestapplication component應用元件(yii\web\Request類的例項) 獲得訪問相應的請求物件。

響應

當一個應用在處理完一個請求後, 這個應用會生成一個response響應物件並把這個響應物件傳送給終端使用者 這個響應物件包含的資訊有 HTTP 狀態碼,HTTP 頭和主體內容等, 從本質上說,網頁應用開發最終的目標就是根據不同的請求去構建這些響應物件。

在大多數實際應用情況下,你應該主要地去處理response這個應用元件, 在預設情況下,它是一個繼承自yii\web\Response的例項 然而,Yii 也允許你建立自己的響應物件併發送給終端使用者

Cookie 驗證

在上兩節中,當通過requestresponse元件讀取和傳送 cookie 時, 你會喜歡擴充套件的 cookie 驗證的保障安全功能,它能 使 cookie 不被客戶端修改。該功能通過給每個 cookie 簽發一個雜湊字串來告知服務端 cookie 是否在客戶端被修改, 如果被修改,通過request元件的cookie collectioncookie 集合訪問不到該 cookie。

注意:Cookie 驗證只保護 cookie 值被修改,如果一個 cookie 驗證失敗, 仍然可以通過$_COOKIE來訪問該 cookie, 因為這是第三方庫對未通過 cookie 驗證自定義的操作方式。

Cookie 驗證預設啟用,可以設定yii\web\Request::$enableCookieValidation屬性為 false 來禁用它, 儘管如此,我們強烈建議啟用它。

注意:直接通過$_COOKIEsetcookie()讀取和傳送的 Cookie 不會被驗證。

當使用 cookie 驗證時,必須指定yii\web\Request::$cookieValidationKey,它是用來生成上述的雜湊值, 可通過在應用配置中配置request元件。

錯誤處理

Yii 內建了一個error handler錯誤處理器,它使錯誤處理更方便, Yii錯誤處理器做以下工作來提升錯誤處理效果:

  • 所有非致命PHP錯誤(如,警告,提示)會轉換成可獲取異常;
  • 異常和致命的PHP錯誤會被顯示, 在除錯模式會顯示詳細的函式呼叫棧和原始碼行數。
  • 支援使用專用的控制器操作來顯示錯誤;
  • 支援不同的錯誤響應格式;

error handler錯誤處理器預設啟用, 可通過在應用的入口指令碼中定義常量YII_ENABLE_ERROR_HANDLER來禁用。

使用錯誤處理器

error handler註冊成一個名稱為errorHandler應用元件, 可以在應用配置中配置它類似如下:

自定義錯誤顯示

error handler錯誤處理器根據常量YII_DEBUG的值來調整錯誤顯示, 當YII_DEBUG為 true (表示在除錯模式), 錯誤處理器會顯示異常以及詳細的函式呼叫棧和原始碼行數來幫助除錯, 當YII_DEBUG為 false,只有錯誤資訊會被顯示以防止應用的敏感資訊洩漏。

使用錯誤動作

使用指定的錯誤操作來自定義錯誤顯示更方便, 為此,首先配置errorHandler元件的errorAction屬性, 類似如下:

日誌

Yii提供了一個強大的日誌框架,這個框架具有高度的可定製性和可擴充套件性。使用這個框架, 你可以輕鬆地記錄各種型別的訊息,過濾它們, 並且將它們收集到不同的目標,諸如檔案,資料庫,郵件。

使用Yii日誌框架涉及下面的幾個步驟:

  • 在你程式碼裡的各個地方記錄log messages
  • 在應用配置裡通過配置log targets來過濾和匯出日誌訊息;
  • 檢查由不同的目標匯出的已過濾的日誌訊息(例如:Yii debugger)。

日誌訊息

記錄日誌訊息就跟呼叫下面的日誌方法一樣簡單:

  • Yii::trace():記錄一條訊息去跟蹤一段程式碼是怎樣執行的。這主要在開發的時候使用。
  • Yii::info():記錄一條訊息來傳達一些有用的資訊。
  • Yii::warning():記錄一個警告訊息用來指示一些已經發生的意外。
  • Yii::error():記錄一個致命的錯誤,這個錯誤應該儘快被檢查。

日誌目標

一個日誌目標是一個yii\log\Target類或者它的子類的例項。 它將通過他們的嚴重層級和類別來過濾日誌訊息,然後將它們匯出到一些媒介中。

Yii配備了以下的內建日誌目標。請參考關於這些類的API文件, 並且學習怎樣配置和使用他們。

訊息過濾

對於每一個日誌目標,你可以配置它的levelscategories屬性來指定哪個訊息的嚴重程度和分類目標應該處理。

如果你沒有指定levels的屬性, 那就意味著目標將處理任何嚴重程度的訊息。

categories屬性是一個包含訊息分類名稱或者模式的陣列。 一個目標將只處理那些在這個陣列中能夠找到對應的分類或者其中一個相匹配的模式的訊息。 一個分類模式是一個以星號*結尾的分類名字首。假如一個分類名與分類模式具有相同的字首, 那麼該分類名將和分類模式相匹配。例如,yii\db\Command::executeyii\db\Command::query都是作為分類名稱運用在yii\db\Command類來記錄日誌訊息的。 它們都是匹配模式yii\db\*

假如你沒有指定categories屬性, 這意味著目標將會處理任何分類的訊息。

訊息格式化

日誌目標以某種格式匯出過濾過的日誌訊息。例如, 假如你安裝一個yii\log\FileTarget類的日誌目標, 你應該能找出一個日誌訊息類似下面的runtime/log/app.log檔案:

2014-10-04 18:10:15 [::1][][-][trace][yii\base\Module::getModule] Loading module: debug

日誌目標也可以追加一些上下文資訊到每組日誌訊息中。 預設情況下,這些全域性的PHP變數的值被包含在:$_GET$_POST$_FILES$_COOKIE$_SESSION$_SERVER中。 你可以通過配置yii\log\Target::$logVars屬性適應這個行為, 這個屬性是你想要通過日誌目標包含的全域性變數名稱。 舉個例子,下面的日誌目標配置指明瞭只有$_SERVER變數的值將被追加到日誌訊息中。

訊息跟蹤級別

在開發的時候,通常希望看到每個日誌訊息來自哪裡。這個是能夠被實現的,通過配置log元件的traceLevel屬性

訊息重新整理和匯出

如上所述,通過logger object物件,日誌訊息被儲存在一個數組裡。 為了這個陣列的記憶體消耗,當陣列積累了一定數量的日誌訊息, 日誌物件每次都將重新整理被記錄的訊息到log targets中。 你可以通過配置log元件的flushInterval屬性來自定義數量:

切換日誌目標

你可以通過配置enabled屬性來開啟或者禁用日誌目標。 你可以通過日誌目標配置去做,或者是在你的程式碼中放入下面的PHP申明:

效能分析

效能分析是一個特殊的訊息記錄型別,它通常用在測量某段程式碼塊的時間, 並且找出效能瓶頸是什麼。舉個例子,yii\db\Command類 使用效能分析找出每個資料庫查詢的時間。

為了使用效能分析,首先確定需要進行分析的程式碼塊。 然後像下面這樣圍住每個程式碼塊:

這裡的myBenchmark代表一個唯一標記來標識一個程式碼塊。之後當你檢查分析結果的時候, 你將使用這個標記來定位對應的程式碼塊所花費的時間。

對於確保beginProfile和endProfile對能夠正確地巢狀,這是很重要的。 例如,

Linux等環境軟體安裝