yii2配置restful接口返回分页信息


最近脑洞大开想尝试使用yii2的restful,这能省很多时间。可以解放双手把精力集中在真正需要解决的问题上。但是在我尝试获取api的列表的时候发现程序默认的奖列表分页信息写在响应头里面了。感觉这样也可以,直接返回列表,数据看起来更漂亮。

浏览区获取到的Header的结果分页信息确实存在:
X-Pagination-Current-Page 1
X-Pagination-Page-Count 5
X-Pagination-Per-Page 20
X-Pagination-Total-Count 84

但是js却始终获取不到X-Pagination-Page-Count,下面是在ajax的success里面执行的一段代码。

console.log("xhr:", xhr.getAllResponseHeaders());
console.log("page_count:", xhr.getResponseHeader("X-Pagination-Page-Count"));
console.log("page:", xhr.getResponseHeader("X-Pagination-Current-Page"));
console.log("page:", xhr.getResponseHeader("x-pagination-current-page"));

js的运行结果:
xhr:X-Pagination-Current-Page: 1
Content-Type: application/json; charset=UTF-8
page_count: null
page: 1
page: 1

我反复尝试,无论如何调整参数名称始终没有得到想要的结果,不知道为什么XMLHttpRequest似乎过滤了那些参数。我有点绝望。

也许我的车子不适合别人造的轮子,可能我要自己造轮子了。我想到几个办法:
1. 重写控制器的action,自己定义数据的输出格式,我不喜欢这个做法,还要维护很多非业务代码。
2. 重写Serializer,这个是我比较能接受的办法,还可以重用,虽然不完美,但是可接受。

于是我简单看了一下yii\rest\Serializer类,就自己写了一个。并且覆盖了yii\rest\Controller中$serializer的值:我准备重写yii\rest\Serializer的serializeDataProvider方法的时候发现,我差点给自己挖了一个大坑。yii\rest\Serializer中定义了一个collectionEnvelope。它是这样用的:

if ($this->request->getIsHead()) {
            return null;
        } elseif ($this->collectionEnvelope === null) {
            return $models;
        } else {
            $result = [
                $this->collectionEnvelope => $models,
            ];
            if ($pagination !== false) {
                return array_merge($result, $this->serializePagination($pagination));
            } else {
                return $result;
            }
        }

然后我在我的控制器里面重写了init()方法:

    public function init(){
        parent::init();
        $this->serializer=[
            'class'=>$this->serializer,
            'collectionEnvelope'=>'items',
            ];

    }

完美!这才是要想要的结果。

Archives