2 位追蹤者

回應

當應用程式完成處理請求時,它會生成一個回應物件並將其發送給終端使用者。回應物件包含諸如 HTTP 狀態碼、HTTP 標頭和主體等資訊。Web 應用程式開發的最終目標本質上是根據各種請求建構此類回應物件。

在大多數情況下,您應該主要處理 response 應用程式組件,預設情況下它是 yii\web\Response 的實例。但是,Yii 也允許您建立自己的回應物件並將其發送給終端使用者,我們將在下面解釋。

在本節中,我們將描述如何撰寫回應並將其發送給終端使用者。

狀態碼

建構回應時,您要做的第一件事是聲明請求是否已成功處理。這是通過設定 yii\web\Response::$statusCode 屬性來完成的,該屬性可以採用有效的 HTTP 狀態碼 之一。例如,要指示請求已成功處理,您可以將狀態碼設定為 200,如下所示

Yii::$app->response->statusCode = 200;

但是,在大多數情況下,您不需要顯式設定狀態碼。這是因為 yii\web\Response::$statusCode 的預設值為 200。如果您想指示請求不成功,您可以拋出適當的 HTTP 例外,如下所示

throw new \yii\web\NotFoundHttpException;

錯誤處理器捕獲到例外時,它將從例外中提取狀態碼並將其分配給回應。對於上面的 yii\web\NotFoundHttpException,它與 HTTP 狀態 404 相關聯。以下 HTTP 例外在 Yii 中預先定義

如果您要拋出的例外不在上述列表中,您可以通過從 yii\web\HttpException 擴展來建立一個,或者直接使用狀態碼拋出它,例如,

throw new \yii\web\HttpException(402);

HTTP 標頭

您可以通過操作 response 組件中的 標頭集合來發送 HTTP 標頭。例如,

$headers = Yii::$app->response->headers;

// add a Pragma header. Existing Pragma headers will NOT be overwritten.
$headers->add('Pragma', 'no-cache');

// set a Pragma header. Any existing Pragma headers will be discarded.
$headers->set('Pragma', 'no-cache');

// remove Pragma header(s) and return the removed Pragma header values in an array
$values = $headers->remove('Pragma');

資訊:標頭名稱不區分大小寫。並且新註冊的標頭在調用 yii\web\Response::send() 方法之前不會發送給使用者。

回應主體

大多數回應都應該有一個主體,其中包含您要向終端使用者顯示的內容。

如果您已經有一個格式化的主體字串,您可以將其分配給回應的 yii\web\Response::$content 屬性。例如,

Yii::$app->response->content = 'hello world!';

如果您的資料在發送給終端使用者之前需要格式化,您應該同時設定 formatdata 屬性。format 屬性指定 data 應該格式化為哪種格式。例如,

$response = Yii::$app->response;
$response->format = \yii\web\Response::FORMAT_JSON;
$response->data = ['message' => 'hello world'];

Yii 開箱即用支援以下格式,每種格式都由 formatter 類別實現。您可以通過配置 yii\web\Response::$formatters 屬性來自訂這些格式化器或添加新的格式化器。

雖然回應主體可以如上所示顯式設定,但在大多數情況下,您可以通過 action 方法的返回值隱式設定它。一個常見的用例是這樣的

public function actionIndex()
{
    return $this->render('index');
}

上面的 index 動作返回 index 視圖的渲染結果。返回值將由 response 組件獲取、格式化,然後發送給終端使用者。

因為預設情況下回應格式是 HTML,所以您應該只在 action 方法中返回字串。如果您想使用不同的回應格式,您應該先設定它,然後再返回資料。例如,

public function actionInfo()
{
    \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
    return [
        'message' => 'hello world',
        'code' => 100,
    ];
}

如前所述,除了使用預設的 response 應用程式組件外,您還可以建立自己的回應物件並將其發送給終端使用者。您可以通過在 action 方法中返回此類物件來做到這一點,如下所示,

public function actionInfo()
{
    return \Yii::createObject([
        'class' => 'yii\web\Response',
        'format' => \yii\web\Response::FORMAT_JSON,
        'data' => [
            'message' => 'hello world',
            'code' => 100,
        ],
    ]);
}

注意:如果您要建立自己的回應物件,您將無法利用您在應用程式配置中為 response 組件設定的配置。但是,您可以使用依賴注入將通用配置應用於您的新回應物件。

瀏覽器重定向

瀏覽器重定向依賴於發送 Location HTTP 標頭。由於此功能很常用,因此 Yii 為其提供了一些特殊支援。

您可以通過調用 yii\web\Response::redirect() 方法將使用者瀏覽器重定向到 URL。該方法使用給定的 URL 設定適當的 Location 標頭,並返回回應物件本身。在 action 方法中,您可以調用其快捷版本 yii\web\Controller::redirect()。例如,

public function actionOld()
{
    return $this->redirect('https://example.com/new', 301);
}

在上面的程式碼中,action 方法返回 redirect() 方法的結果。如前所述,action 方法返回的回應物件將用作發送給終端使用者的回應。

在 action 方法以外的地方,您應該直接調用 yii\web\Response::redirect(),然後鏈式調用 yii\web\Response::send() 方法,以確保不會將額外內容附加到回應中。

\Yii::$app->response->redirect('https://example.com/new', 301)->send();

資訊:預設情況下,yii\web\Response::redirect() 方法將回應狀態碼設定為 302,這指示瀏覽器請求的資源暫時位於不同的 URI 中。您可以傳入狀態碼 301,以告知瀏覽器資源已永久重新定位。

當目前請求是 AJAX 請求時,發送 Location 標頭不會自動導致瀏覽器重定向。為了解决這個問題,yii\web\Response::redirect() 方法設定一個 X-Redirect 標頭,並將重定向 URL 作為其值。在客戶端,您可以編寫 JavaScript 程式碼來讀取此標頭值並相應地重定向瀏覽器。

資訊:Yii 配有一個 yii.js JavaScript 檔案,它提供了一組常用的 JavaScript 實用程式,包括基於 X-Redirect 標頭的瀏覽器重定向。因此,如果您正在使用此 JavaScript 檔案(通過註冊 yii\web\YiiAsset 資源包),則無需編寫任何程式碼來支援 AJAX 重定向。有關 yii.js 的更多資訊,請參閱客戶端腳本章節

傳送檔案

與瀏覽器重定向類似,檔案傳送是另一個依賴於特定 HTTP 標頭的功能。Yii 提供了一組方法來支援各種檔案傳送需求。它們都內建支援 HTTP range 標頭。

這些方法具有相同的方法簽名,並以回應物件作為返回值。如果要發送的檔案非常大,您應該考慮使用 yii\web\Response::sendStreamAsFile(),因為它更節省記憶體。以下範例示範如何在控制器 action 中發送檔案

public function actionDownload()
{
    return \Yii::$app->response->sendFile('path/to/file.txt');
}

如果您在 action 方法以外的地方調用檔案傳送方法,您也應該在之後調用 yii\web\Response::send() 方法,以確保不會將額外內容附加到回應中。

\Yii::$app->response->sendFile('path/to/file.txt')->send();

某些 Web 伺服器具有稱為 X-Sendfile 的特殊檔案傳送支援。其想法是將檔案請求重定向到 Web 伺服器,Web 伺服器將直接提供檔案。因此,Web 應用程式可以在 Web 伺服器發送檔案時更早終止。要使用此功能,您可以調用 yii\web\Response::xSendFile()。以下列表總結了如何為某些流行的 Web 伺服器啟用 X-Sendfile 功能

傳送回應

在調用 yii\web\Response::send() 方法之前,回應中的內容不會發送給使用者。預設情況下,此方法將在 yii\base\Application::run() 結束時自動調用。但是,您可以顯式調用此方法以強制立即發送回應。

yii\web\Response::send() 方法採用以下步驟發送回應

  1. 觸發 yii\web\Response::EVENT_BEFORE_SEND 事件。
  2. 調用 yii\web\Response::prepare()回應資料格式化為 回應內容
  3. 觸發 yii\web\Response::EVENT_AFTER_PREPARE 事件。
  4. 調用 yii\web\Response::sendHeaders() 以發送已註冊的 HTTP 標頭。
  5. 調用 yii\web\Response::sendContent() 以發送回應主體內容。
  6. 觸發 yii\web\Response::EVENT_AFTER_SEND 事件。

yii\web\Response::send() 方法被調用一次後,任何後續對此方法的調用都將被忽略。這表示一旦回應發送出去,您將無法向其附加更多內容。

如您所見,yii\web\Response::send() 方法觸發了幾個有用的事件。通過回應這些事件,可以調整或裝飾回應。

發現錯字或您認為此頁面需要改進?
在 github 上編輯 !