必须显式使用 $query_string,否则 get 参数会被静默丢弃;正确写法是 try_files $uri $uri/ /index.php?$query_string,$query_string 等价于 $args 且语义更清晰,避免用 $is_args$args 或 /index.php?/$request_uri 等错误变体。

try_files 里漏了 $query_string 就会丢 GET 参数
这是 Laravel 项目最常踩的坑:Nginx 配置中 try_files 写成 try_files $uri $uri/ /index.php;,导致所有 ?page=2、?q=test 类参数在进 PHP 前就被截断。Laravel 的 Request 对象根本收不到,$request->query() 或 request('q') 全为空。
必须显式把查询字符串带进去:
-
try_files $uri $uri/ /index.php?$query_string;—— 推荐,语义清晰,$query_string等价于$args - 不要写
/index.php?$args(虽能用,但 Nginx 官方文档更倾向$query_string) - 避免用
/index.php?/$request_uri这类错误变体,会把整个 URI 当作一个参数名
rewrite 规则里没拼 $args 就是主动丢参
如果你用了 rewrite 做路径调整(比如把 /old 跳到 /new),默认行为是清空所有查询参数。用户访问 /old?utm_source=ads,跳过去只剩 /new。
正确写法必须手动补上:
-
rewrite ^/old(.*)$ /new$1?$args permanent;——$1复原路径尾部,$args补全参数 -
return 301 /new-path?$args;—— 简单跳转直接这么写,最稳 - 千万别写
rewrite ^/old /new permanent;—— 没有$args,也不带(.*),参数必丢
Laravel 11 的 route() 和 url() 函数对 $args 更敏感
Laravel 11 强制要求生成 URL 时保留完整查询上下文。如果 Nginx 的 try_files 或代理层没透传 $args,会导致 route('posts.index', ['page' => 2]) 生成的链接缺 ?page=2,分页失效;表单提交后 _token 也消失,报 419 错误。
验证方式很简单:打开浏览器开发者工具,看 Network 标签页里请求的完整 URL 是否含参数。如果地址栏有 ?page=3 但实际发出去的请求是 /posts,问题就出在 Nginx 层。
- 检查点一:
location /块里的try_files是否含$query_string - 检查点二:有没有其他
rewrite或return规则在中间劫持并丢参 - 检查点三:若用了反向代理(如 API 网关),确认
proxy_pass末尾带斜杠(proxy_pass http://upstream/;),否则参数可能不透传
宝塔面板用户特别注意伪静态模板的坑
宝塔自带的 Laravel 伪静态模板多数是旧版,里面写的是 try_files $uri $uri/ /index.php?$is_args$args;。这个写法本身没错,但 $is_args 是个“条件开关”——只有当原始请求带参数时才输出 ?,否则为空。问题在于:某些 Nginx 版本(尤其是 1.20+)对 $is_args 解析不稳定,偶尔会漏掉 ? 导致 /index.php?foo=bar 变成 /index.phpfoo=bar,PHP 直接 404。
绕过风险的实操建议:
- 删掉
$is_args,统一用/index.php?$query_string - 在宝塔「网站设置 → 伪静态」里手动覆盖模板内容,别依赖一键配置
- 改完立刻执行
nginx -t && nginx -s reload,别只点「保存」
$args,GET 参数就彻底蒸发——而且不会报错,只会静默丢弃。











