织梦伪静态规则冲突排查方法
问题背景
织梦 DedeCMS 开启伪静态后,常出现各种怪现象:列表页能打开但翻页 404、文章 URL 跳到首页、tag 页与栏目页 URL 互相覆盖、移动站伪静态被 PC 站规则抢匹配。这些问题的根因大多是 rewrite 规则之间存在冲突,规则顺序不当,或正则贪婪匹配吃掉了不该吃的 URL。
原因分析
nginx 规则按顺序匹配
nginx location 与 rewrite 是按声明顺序匹配的,先写的规则优先生效。若把通用的 ^/(.*)$ 写在前面,后面所有具体规则都不会被匹配。
正则贪婪匹配
(.*)、(.+) 默认贪婪,会尽可能多地吃字符。例如 ^/list-([0-9]+)-([0-9]+)\.html$ 与 ^/list-(.*)\.html$ 同时存在时,后者会先匹配成功。
多 location 优先级
nginx 中 location=(精确)> location ^~(前缀)> location ~(正则)。前缀与正则混用时常出现非预期匹配。
解决步骤
一、复现并定位冲突 URL
用 curl 模拟请求,看实际命中哪条规则:
curl -I https://www.example.com/news/1.html
curl -I https://www.example.com/list-1-2.html
二、开启 nginx rewrite 日志
error_log /var/log/nginx/error.log notice;
rewrite_log on;
重启 nginx 后再次请求,error.log 中会打印每条 rewrite 的执行过程,可以清楚看到哪条规则被命中、跳到了哪个 URL。
三、规则按精确度排序
原则:精确的规则在前,模糊的规则在后:
# 1. 精确页面
location=/sitemap.xml { ... }
location=/robots.txt { ... }
# 2. 列表页带翻页
location ~ ^/list-([0-9]+)-([0-9]+)\.html$ {
rewrite ^ /plus/list.php?tid=$1&PageNo=$2 last;
}
# 3. 列表页不带翻页
location ~ ^/list-([0-9]+)\.html$ {
rewrite ^ /plus/list.php?tid=$1 last;
}
# 4. 文章页
location ~ ^/news/([0-9]+)\.html$ {
rewrite ^ /plus/view.php?aid=$1 last;
}
# 5. 兜底(最后)
location / { try_files $uri $uri/ /index.php; }
四、Apache 站点的排查
Apache 的 .htaccess 中 RewriteRule 也按顺序匹配。开启日志:
RewriteLog "/var/log/apache2/rewrite.log"
RewriteLogLevel 3
注意 Apache 2.4+ 已废弃上述指令,需在 vhost 配置中用 RewriteRule 调试。
五、解决移动站规则冲突
PC 与移动站共用一个 nginx 配置时,要按 host 分开:
server {
server_name www.example.com;
# PC 规则
}
server {
server_name m.example.com;
# 移动规则
}
避免在一个 server 块里用 if 判断 host,性能差且易错。
配置示例汇总
注意事项
- nginx 中
rewrite的 flag 用last还是break容易混淆:last会重新走 location 匹配,break不再匹配。织梦伪静态多数用last。 - 开启
rewrite_log会显著增加 IO 负载,调试完务必关闭。 - .htaccess 修改后立即生效,nginx 修改后需
nginx -t && nginx -s reload。 - CDN 缓存可能让你以为规则没生效,调试时记得先清 CDN 缓存或绕过 CDN。
- 规则中正则元字符(如
.、?)需正确转义,否则匹配范围不可控。
实施建议
建议把站点所有 rewrite 规则集中维护在一份 nginx include 文件中,按"精确 → 列表 → 文章 → tag → 兜底"顺序分组并加注释。每次新增规则先用 nginx -t 验证语法,再 curl 测试几个边界 URL(带参数、翻页、特殊字符),确认无冲突后再 reload。长期看,规则越少越好,能用 try_files 解决的就不要写 rewrite,能让站点伪静态逻辑保持简洁可维护。