1 追蹤者

回應格式化

當處理 RESTful API 請求時,應用程式通常會採取以下與回應格式化相關的步驟

  1. 決定可能影響回應格式的各種因素,例如媒體類型、語言、版本等。此過程也稱為內容協商
  2. 將資源物件轉換為陣列,如資源章節所述。這由 yii\rest\Serializer 完成。
  3. 將陣列轉換為內容協商步驟所決定的格式字串。這由向 response 應用程式組件formatters 屬性註冊的 response formatters 完成。

內容協商

Yii 透過 yii\filters\ContentNegotiator 過濾器支援內容協商。RESTful API 基礎控制器類別 yii\rest\Controller 配備了名為 contentNegotiator 的過濾器。此過濾器提供回應格式協商以及語言協商。例如,如果 RESTful API 請求包含以下標頭,

Accept: application/json; q=1.0, */*; q=0.1

它將獲得 JSON 格式的回應,如下所示

$ curl -i -H "Accept: application/json; q=1.0, */*; q=0.1" "https://127.0.0.1/users"

HTTP/1.1 200 OK
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
X-Powered-By: PHP/5.4.20
X-Pagination-Total-Count: 1000
X-Pagination-Page-Count: 50
X-Pagination-Current-Page: 1
X-Pagination-Per-Page: 20
Link: <http://127.0.0.1/users?page=1>; rel=self,
      <http://127.0.0.1/users?page=2>; rel=next,
      <http://127.0.0.1/users?page=50>; rel=last
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

[
    {
        "id": 1,
        ...
    },
    {
        "id": 2,
        ...
    },
    ...
]

在幕後,在執行 RESTful API 控制器動作之前,yii\filters\ContentNegotiator 過濾器將檢查請求中的 Accept HTTP 標頭,並將回應格式設定為 'json'。在動作執行完畢並傳回結果資源物件或集合後,yii\rest\Serializer 會將結果轉換為陣列。最後,yii\web\JsonResponseFormatter 會將陣列序列化為 JSON 字串,並將其包含在回應 body 中。

預設情況下,RESTful API 同時支援 JSON 和 XML 格式。若要支援新的格式,您應該在 API 控制器類別中,像以下範例一樣配置 contentNegotiator 過濾器的 formats 屬性

use yii\web\Response;

public function behaviors()
{
    $behaviors = parent::behaviors();
    $behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_HTML;
    return $behaviors;
}

formats 屬性的鍵是支援的 MIME 類型,而值是相應的回應格式名稱,這些名稱必須在 yii\web\Response::$formatters 中受到支援。

資料序列化

如上所述,yii\rest\Serializer 是將資源物件或集合轉換為陣列的核心組件。它識別實作 yii\base\Arrayable 以及 yii\data\DataProviderInterface 的物件。前者主要由資源物件實作,後者由資源集合實作。

您可以透過設定 yii\rest\Controller::$serializer 屬性與配置陣列來配置序列化器。例如,有時您可能希望透過將分頁資訊直接包含在回應 body 中來簡化客戶端開發工作。為此,請配置 yii\rest\Serializer::$collectionEnvelope 屬性,如下所示

use yii\rest\ActiveController;

class UserController extends ActiveController
{
    public $modelClass = 'app\models\User';
    public $serializer = [
        'class' => 'yii\rest\Serializer',
        'collectionEnvelope' => 'items',
    ];
}

然後,您可以針對請求 https://127.0.0.1/users 獲得以下回應

HTTP/1.1 200 OK
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
X-Powered-By: PHP/5.4.20
X-Pagination-Total-Count: 1000
X-Pagination-Page-Count: 50
X-Pagination-Current-Page: 1
X-Pagination-Per-Page: 20
Link: <http://127.0.0.1/users?page=1>; rel=self,
      <http://127.0.0.1/users?page=2>; rel=next,
      <http://127.0.0.1/users?page=50>; rel=last
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

{
    "items": [
        {
            "id": 1,
            ...
        },
        {
            "id": 2,
            ...
        },
        ...
    ],
    "_links": {
        "self": {
            "href": "https://127.0.0.1/users?page=1"
        },
        "next": {
            "href": "https://127.0.0.1/users?page=2"
        },
        "last": {
            "href": "https://127.0.0.1/users?page=50"
        }
    },
    "_meta": {
        "totalCount": 1000,
        "pageCount": 50,
        "currentPage": 1,
        "perPage": 20
    }
}

控制 JSON 輸出

JSON 回應由 JsonResponseFormatter 類別產生,該類別將在內部使用 JSON 輔助程式。此格式化器可以使用不同的選項進行配置,例如 $prettyPrint 選項,此選項在開發時對於提高回應的可讀性很有用,或 $encodeOptions 選項,用於控制 JSON 編碼的輸出。

可以在應用程式 配置 中,於 response 應用程式組件的 formatters 屬性中配置格式化器,如下所示

'response' => [
    // ...
    'formatters' => [
        \yii\web\Response::FORMAT_JSON => [
            'class' => 'yii\web\JsonResponseFormatter',
            'prettyPrint' => YII_DEBUG, // use "pretty" output in debug mode
            'encodeOptions' => JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE,
            // ...
        ],
    ],
],

當使用 DAO 資料庫層從資料庫傳回資料時,所有資料都將表示為字串,這並不總是預期的結果,尤其是在 JSON 中,數值應該表示為數字。當使用 ActiveRecord 層從資料庫檢索資料時,從資料庫中提取資料時,數值欄位的值將在 yii\db\ActiveRecord::populateRecord() 中轉換為整數。

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