1 关注者

响应格式

当处理 RESTful API 请求时,应用程序通常会采取以下与响应格式相关的步骤

  1. 确定可能影响响应格式的各种因素,例如媒体类型、语言、版本等。此过程也称为 内容协商
  2. 将资源对象转换为数组,如 资源 部分所述。这是由 yii\rest\Serializer 完成的。
  3. 将数组转换为字符串,格式由内容协商步骤确定。这是由 响应格式器 完成的,这些格式器已注册到 formatters 属性中 response应用程序组件 中。

内容协商

Yii 通过 yii\filters\ContentNegotiator 过滤器支持内容协商。RESTful API 基本控制器类 yii\rest\ControllercontentNegotiator 名称下配备了此过滤器。该过滤器提供响应格式协商以及语言协商。例如,如果 RESTful API 请求包含以下标头,

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

它将获得 JSON 格式的响应,如下所示

$ curl -i -H "Accept: application/json; q=1.0, */*; q=0.1" "http://localhost/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://localhost/users?page=1>; rel=self,
      <http://localhost/users?page=2>; rel=next,
      <http://localhost/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 字符串,并将其包含在响应正文中。

默认情况下,RESTful API 支持 JSON 和 XML 格式。要支持新的格式,您应该在 API 控制器类中像下面这样配置 formats 属性 contentNegotiator 过滤器

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 属性来配置序列化器。例如,有时您可能希望通过在响应正文中直接包含分页信息来帮助简化客户端开发工作。为此,请将 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',
    ];
}

您可能会收到以下请求 http://localhost/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://localhost/users?page=1>; rel=self,
      <http://localhost/users?page=2>; rel=next,
      <http://localhost/users?page=50>; rel=last
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

{
    "items": [
        {
            "id": 1,
            ...
        },
        {
            "id": 2,
            ...
        },
        ...
    ],
    "_links": {
        "self": {
            "href": "http://localhost/users?page=1"
        },
        "next": {
            "href": "http://localhost/users?page=2"
        },
        "last": {
            "href": "http://localhost/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 上编辑它 !