推荐使用 rewrite ^/list/(\d+)(?.*)?$ /list.php?page=$1$2 last; 精确捕获页码及原始查询参数,确保 $_get 同时获得 page 和 keyword 等参数,地址栏不变且兼容搜索条件透传。

把带数字分页的列表页(比如 /list.php?page=2)转成语义化链接(如 /list/page/2 或 /list/2),核心是用 rewrite 捕获页码并映射回带参路径,同时确保后端能正常接收参数、不丢原始查询串(如搜索关键词、分类 ID 等)。
基础语义化分页规则(推荐 /list/2 形式)
适用于简单分页,无额外参数场景:
- 在
location /list块或server块中添加:rewrite ^/list/(\d+)$ /list.php?page=$1 last; - 正则
^/list/(\d+)$精确匹配/list/2、/list/15,避免误伤/list/category这类路径 -
$1是捕获的页码,拼进目标 URL,last触发重新匹配 location,保证 PHP 能被正确处理
保留原始查询参数(如带搜索条件)
用户可能访问的是 /list/3?keyword=nginx&cat=web,重写后需让 list.php 同时收到 page=3 和原始参数:
- 改用
try_files+$query_string更稳妥:location /list { try_files $uri $uri/ /list.php?page=$1&$query_string; }
但注意:这种写法需配合正则捕获,实际更推荐下面方式 - 更通用做法:先用 rewrite 提取页码,再手动拼接完整 query:
rewrite ^/list/(\d+)(\?.*)?$ /list.php?page=$1$2 last;
其中(\?.*)?可选捕获原始查询字符串(含 ?),$2直接追加,保持参数完整
统一入口路由(适合 ThinkPHP/Laravel 等框架)
如果项目走单入口(如所有请求都经 index.php),不建议对每个分页单独写 rewrite,而是用 try_files 一次兜底:
-
location /list { try_files $uri $uri/ /index.php?s=/list/page/$1&$query_string; }
但需注意:$1 在 try_files 中不可用,所以应改用更健壮的写法 - 推荐直接用:
location /list { try_files $uri $uri/ /index.php?$query_string; }
然后在 PHP 路由层解析路径(如解析$_SERVER['REQUEST_URI']得到/list/2),再提取页码。这样更灵活,也避免 rewrite 嵌套陷阱
验证与调试要点
配置完别急着上线,用 curl 实测真实行为:
- 检查是否内部重写(地址栏不变):
curl -I http://yoursite.com/list/2→ 应返回 200,不是 301/302 - 检查参数是否透传:
curl "http://yoursite.com/list/2?keyword=test"→ 后端$_GET应同时有page=2和keyword=test - 开启 rewrite_log(临时)辅助排查:
rewrite_log on;+error_log /var/log/nginx/rewrite.log notice;











