应避免用request()->except('page')做分页参数透传,因其混淆GET/POST来源、忽略自定义页码键名、导致URL膨胀;正确做法是request()->get()结合array_diff_key()显式过滤分页键,并在API场景下手动构造白名单查询参数。

别用 request()->except() 做分页参数透传 —— 它会漏掉关键参数,且无法处理 page 字段的语义冲突。
为什么 request()->except('page') 不适合分页透传
很多人看到“去掉 page 参数保留其他 GET 参数”就直觉写 request()->except('page'),但这个操作在分页场景下有三个硬伤:
-
except()返回的是扁平数组,不区分来源(GET/POST/路由),而分页链接只应透传 URL 查询参数(即 GET); - 它无法识别别名 page 参数,比如你配置了
'page' => 'p',except('page')对p=2完全无效; - 如果请求里混着 POST 数据(如 AJAX 提交带搜索条件),
except()会把 POST 参数也塞进分页链接,导致 URL 膨胀甚至 414 错误。
正确做法:用 request()->get() + array_diff_key()
分页透传必须限定为 GET 参数,并显式排除分页控制字段。推荐组合:
- 用
request()->get()确保只取 URL 查询字符串里的键值; - 用
array_diff_key()过滤掉所有可能的分页键,不止page,还要包括p、page_no等自定义别名; - 不要依赖框架自动识别,自己列清楚要剔除的键名。
示例:
立即学习“PHP免费学习笔记(深入)”;
$query = array_diff_key(request()->get(), ['page' => '', 'p' => '', 'page_no' => '']);
$users = User::where('status', 1)->paginate(15, false, ['query' => $query]);
API 场景下不能依赖 request()->get()
如果是 POST JSON 请求(如 Vue/React 前端调用),request()->get() 永远为空 —— 此时 query 必须手动构造:
- 搜索关键词、分类 ID、状态等非分页字段,应从
request()->param()或验证后数据中提取; - 避免直接 dump 整个
request()->param(),防止敏感字段(如 token、sign)泄露到分页链接; - 建议封装一个白名单函数,比如
getSearchParams(),只返回允许透传的字段。
appends() 是补救手段,不是替代方案
如果你已在控制器里用了 query 配置,又额外调 $list->appends(['lang' => 'zh']),注意:
- 同名键会被
appends()覆盖,比如query里有['keyword' => 'php'],appends(['keyword' => 'go'])后最终链接是?keyword=go&page=3; -
appends()必须在render()前调用,且不能链式写在paginate()后面(因为paginate()返回对象,但appends()不改变原对象,需赋值或链式接续); - 模板里
{$list->render()|raw}才生效,单独 echo$list->appends(...)没用。
真正容易被忽略的是:分页参数是否来自路由变量(如 /search/:keyword)、是否启用了 URL 兼容模式(url_common)、以及多级嵌套参数(如 filter[status]=1&filter[type]=blog)——这些都无法靠 except() 安全处理,必须回归到「明确知道要透传什么」这个前提上。



















