ThinkPHP分页保留GET参数失败的根本原因是appends()调用时机错误或参数类型不合法:必须在paginate()后、渲染前调用,且只接受过滤后的标量数组,需排除page等系统键并确保无null/数组值。

ThinkPHP 分页保留 GET 参数为什么 appends() 不生效
根本原因不是方法写错了,而是你调用 appends() 的时机或参数类型不对。它只接受数组,但很多人直接传了 $_GET(可能含空值、敏感键如 page),或者在分页对象生成后才调用——这时已晚。
常见错误现象:?page=2 点下一页变成 ?page=3,但其他参数如 keyword=test 消失;或者报错 Invalid argument supplied for foreach()。
- 必须在调用
paginate()之后、但在模板渲染前调用appends() - 不要直接传
$_GET,先过滤掉分页系统自己用的键(如page、limit) - 确保所有要保留的参数都是字符串或数字,避免
null或数组(如checkbox[]=a&checkbox[]=b会出问题)
手动构造安全的 appends 数组:过滤 + 类型校验
ThinkPHP 不会自动帮你剔除分页相关参数,也不处理嵌套数组,所以得自己来。重点是保留业务参数,排除干扰项。
典型使用场景:搜索列表页带关键词 keyword、分类 cat_id、状态 status,但不想让 page 重复出现在 URL 里。
立即学习“PHP免费学习笔记(深入)”;
- 用
input('param.')替代$_GET,它已做过基础过滤和类型归一 - 显式排除
page、limit、sort等分页/排序参数 - 对每个值做
is_scalar()判断,跳过数组或 null 值(否则appends()内部会警告或丢弃)
示例代码片段:
$map = input('param.');
unset($map['page'], $map['limit']);
$append = [];
foreach ($map as $k => $v) {
if (is_scalar($v)) {
$append[$k] = $v;
}
}
$list = Db::name('article')->where($where)->paginate(10);
$list->appends($append);
模板中输出分页时,URL 查询字符串被双重编码
这不是 appends() 的锅,而是你手动拼接链接或用了过时的模板写法。ThinkPHP 5.1+ 的 $list->render() 默认会对参数做 urlencode(),如果你再在外层用 url() 或自己拼 http_build_query(),就会出现 %252F 这种套娃编码。
性能影响不大,但用户点开链接会 404 或参数解析失败。
- 模板里直接用
{$list->render|raw},别自己解析$list->links() - 不要在模板里用
{:url('index',['page'=>2,'keyword'=>$keyword])}来生成分页链接——这绕过了appends机制 - 如果必须自定义分页 HTML,用
$list->getUrlRange(1,5)配合$list->appends()返回的参数数组,而不是手撕 query string
多级路径或子域名下 appends 丢失参数的兼容性问题
当项目部署在子目录(如 https://example.com/admin/)或用了二级域名(admin.example.com),部分 Nginx/Apache 配置会导致 $_SERVER['QUERY_STRING'] 截断,进而使 input('param.') 拿不到完整参数。
这不是框架 bug,是服务器环境没把原始查询字符串透传给 PHP。
- 检查 Nginx 的
fastcgi_param QUERY_STRING $query_string;是否存在且未被覆盖 - Apache 下确认
mod_rewrite规则末尾有[QSA]标志(如RewriteRule ^(.*)$ index.php?/$1 [L,QSA]) - 临时验证方式:在控制器开头加
dump($_SERVER['QUERY_STRING']);,看是否完整输出page=2&keyword=test
参数一旦在入口就丢了,后面怎么 appends 都没用——这点最容易被忽略,排查时优先看服务器日志和 $_SERVER 快照。



















