最近脑洞大开想尝试使用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', ]; }
完美!这才是要想要的结果。