yii restful接口需手动实现搜索与分页:用andfilterwhere()处理多条件并过滤空值,统一参数获取方式,显式类型转换,避免count()与查询不一致,前端需encodeuricomponent()处理特殊字符。

Yii 框架的 RESTful 接口本身不内置搜索逻辑,必须手动在 actionIndex() 或自定义动作里解析请求参数、构建查询条件并应用分页 —— 否则所有请求都会返回全量数据。
RESTful 控制器中如何接收并处理多条件参数
Yii 的 REST 控制器默认从 GET 查询字符串或 POST/PUT 请求体中提取参数,但不会自动过滤空值。直接用 Yii::$app->request->get('xxx') 拿到的是原始值,包括空字符串、null、甚至字符串 "0",这些都可能意外触发无效条件。
推荐做法是统一用 andFilterWhere() 配合数组条件,它会跳过 isEmpty() 为 true 的值(即 null、''、[]),而 andWhere() 会把空字符串也当有效条件拼进 SQL,导致查不到结果或查出脏数据。
- 用
$request->get()或$request->getBodyParam()获取参数,不建议混合使用 - 对数字类字段(如
status、category_id)做显式类型转换:(int)$request->get('status'),避免字符串比较 - 模糊搜索用
andFilterWhere(['like', 'title', $title]),不要手拼"%{$title}%",防止 SQL 注入 - 时间范围等复合条件建议封装成独立方法,例如
applyDateRange($query, $start, $end)
为什么分页总数 count() 和实际数据 query()->all() 结果不一致
常见原因是:调用 $query->count() 前没复用完全相同的查询对象。比如你在构建查询时先加了 andFilterWhere(),又额外加了 orderBy() 或 with(),而 count() 不支持 with 和大部分 select 修饰,会导致 count 语句和实际查询语义不同。
正确写法是先建好基础 $query,只加 from、where、andFilterWhere 等影响行数的条件,再分别用于 count() 和 all():
$query = Article::find(); $query->andFilterWhere(['status' => $status]); $query->andFilterWhere(['like', 'title', $title]); $count = $query->count(); // ✅ 此时 count 是干净的 $data = $query->offset($offset)->limit($limit)->all(); // ✅ 复用同一 query 对象
- 别在
count()前调用select()、groupBy()、with(),它们会让 count 出错或变慢 - 如果必须
groupBy,改用原生 SQL 或子查询,count()无法正确反映分组后行数 - RESTful 接口返回分页信息时,
totalCount必须来自$query->count(),不能靠count($data)
GET 参数带斜杠或特殊字符导致 404 或解析失败
Yii 默认路由规则会把 URL 中的 /、.、+ 等当作路径分隔符或保留字。例如搜索关键词 "C++ tutorial",传成 ?q=C++ tutorial 会被截断或编码异常;更糟的是 ?path=/api/v1/users 这种带斜杠的值,直接 404。
解决方式不是改路由,而是前端主动 encodeURIComponent(),后端用 urldecode()(通常 Yii 自动处理 GET,但 POST JSON 体需注意):
- 前端发 GET 请求前对每个参数值调用
encodeURIComponent(value) - 后端避免在
rules中用通配符匹配参数名,如'<action:>/<id:>'</id:></action:>会干扰q=xxx - 若必须传复杂结构(如嵌套对象),改用
POST /search+ JSON body,比折腾 URL 更可靠
真正麻烦的不是写几个 andFilterWhere,而是每次加新字段都要同步更新验证规则、数据库索引、前端表单和 API 文档 —— 漏掉任意一环,搜索就变成玄学调试。











