yii2 定制 response 类型

转载 2016-05-18 鲁鲁槟 收藏

一、为何要使用不同的 response 类型

现代的 web 和移动应用(对 Server 的要求)已经不仅仅满足于渲染 HTML 了。

现代的软件架构已渐渐将 UI 看成是一个客户端,客户端负责直接和用户发生交互,整个前端由服务端 API 驱动。

这种情况下 JSON 和 XML 就常常作为结构化数据的序列化和传输的载体在网络上传输,所以创建这种 response 的能力已经成为现代服务框架的必备要求。

二、response 类型

1、你可能知道,yii2 的 action 函数中需要(某种方法)"返回"结果,而不是直接 echo

return $this->render('index', [
    'items' => $items,
]);

2、有个好消息是 yii2 现在可以 return 其他格式的数据,如:

  • 数组

  • 实现了 Arrayable 接口的对象

  • 字符串

  • 实现了 __toString() 方法的对象

只是不要忘了在 return 前设置 \Yii::$app->response->format 来告诉 Yii 你想要 response 的类型:

\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

3、可选的类型有:

  • FORMAT_RAW

  • FORMAT_HTML

  • FORMAT_JSON

  • FORMAT_JSONP

  • FORMAT_XML

默认是FORMAT_HTML

三、JSON response

1、返回一个数组

public function actionIndex()
{
    \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
    $items = ['some', 'array', 'of', 'data' => ['associative', 'array']];
    return $items;
}

返回结果:

{
    "0": "some",
    "1": "array",
    "2": "of",
    "data": ["associative", "array"]
}

注: 如果没有设置 response 类型你会收到一个 exception

2、返回一个对象

public function actionView($id)
{
    \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
    $user = \app\models\User::find($id);
    return $user;
}

这里的 $user 是一个 ActiveRecord 对象,而 ActiveRecord 类已实现了 Arrayable 接口,所以它可以很轻易地被转成 json

{
    "id": 1,
    "name": "John Doe",
    "email": "john@example.com"
}

3、返回一个对象数组

public function actionIndex()
{
    \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
    $users = \app\models\User::find()->all();
    return $users;
}

这里的 $users 就是一个 ActiveRecord 对象数组,不过在底层 yii 是通过 \yii\helpers\Json::encode() 来传输和转化数据的,所以返回的时候请小心确保数组中元素的类型

[
    {
        "id": 1,
        "name": "John Doe",
        "email": "john@example.com"
    },
    {
        "id": 2,
        "name": "Jane Foo",
        "email": "jane@example.com"
    },
    ...
]

四、XML response

1、只要把 response 的 format 改成 FORMAT_XML,,那么你就能得到 XML 类型的返回值

public function actionIndex()
{
    \Yii::$app->response->format = \yii\web\Response::FORMAT_XML;
    $items = ['some', 'array', 'of', 'data' => ['associative', 'array']];
    return $items;
}

//返回
<response>
    <item>some</item>
    <item>array</item>
    <item>of</item>
    <data>
        <item>associative</item>
        <item>array</item>
    </data>
</response>

2、我们同样可以把对象转成 XML

public function actionIndex()
{
    \Yii::$app->response->format = \yii\web\Response::FORMAT_XML;
    $users = \app\models\User::find()->all();
    return $users;
}

//返回
<response>
    <User>
        <id>1</id>
        <name>John Doe</name>
        <email>john@example.com</email>
    </User>
    <User>
        <id>2</id>
        <name>Jane Foo</name>
        <email>jane@example.com</email>
    </User>
</response>

五、定制化自己的response类型

让我们搞一个自己的 response 类型玩玩吧。为了让例子有趣点,我们打算 respond 一个 PHP 数组格式的数据。

1、定制一个 formatter

创建文件 components/PhpArrayFormatter.php

<?php namespace app\components;

use yii\helpers\VarDumper;
use yii\web\ResponseFormatterInterface;

class PhpArrayFormatter implements ResponseFormatterInterface
{
    public function format($response)
    {
        $response->getHeaders()->set('Content-Type', 'text/php; charset=UTF-8');
        if ($response->data !== null) {
            $response->content = "<?php\nreturn " . VarDumper::export($response->data) . ";\n";
        }
    }
}

2、在配置文件中注册这个 formatter

return [
    // ...
    'components' => [
        // ...
        'response' => [
            'formatters' => [
                'php' => 'app\components\PhpArrayFormatter',
            ],
        ],
    ],
];

3、在 controller 里创建一个 action

public function actionTest()
{
    Yii::$app->response->format = 'php';
    return [
        'hello' => 'world!',
    ];
}

4、执行之后的 response 是这样的

<?php return [
    'hello' => 'world!',
];
阅读 1663