PHP本身不处理URL重写,真正起作用的是Apache的mod_rewrite模块或Nginx的rewrite指令;.htaccess仅在AllowOverride All且mod_rewrite启用、文件名严格为.htaccess时才生效。

PHP 本身不处理 URL 重写,真正起作用的是 Apache 的 mod_rewrite 模块或 Nginx 的 rewrite 指令;.htaccess 只是 Apache 下的一种配置载体,且仅在 AllowOverride All 生效时才被读取。
Apache 下 .htaccess 文件必须满足的三个硬性条件
缺一不可,否则规则完全不生效:
-
.htaccess文件名必须严格为.htaccess(开头带英文点、无扩展名),Windows 下用记事本“另存为”时需手动输入".htaccess"(含英文引号); - Apache 主配置中对应目录的
AllowOverride必须设为All,不能是None或FileInfo—— 常见错误是只改了全局<directory></directory>,却漏掉项目实际路径所在的<directory></directory>块; -
mod_rewrite模块必须启用:检查httpd.conf中LoadModule rewrite_module modules/mod_rewrite.so是否已取消注释,然后重启 Apache。
RewriteRule 中 [L] 和 [QSA] 标志为什么不能乱加
这两个标志直接影响参数传递和规则链执行,错配会导致 $_GET 拿不到值、静态资源 404、甚至死循环:
-
[L]表示“最后一条规则”,匹配后立即终止当前轮次处理;漏掉它,后续规则可能继续匹配,比如把/style.css错误重写成index.php?/style.css; -
[QSA](Query String Append)用于保留原始 URL 中的查询参数,例如访问/article/123?utm_source=mail,重写为article.php?id=123后,utm_source会丢失,加[QSA]才能变成article.php?id=123&utm_source=mail; - ThinkPHP 5.1 等框架常用
RewriteRule ^(.*)$ index.php [L,E=PATH_INFO:$1],这里不用[QSA]是因为框架自己解析PATH_INFO,而E=PATH_INFO把路径注入为环境变量供 PHP 读取 —— 若误加[QSA],反而可能干扰$_SERVER['PATH_INFO']的值。
Nginx 没有 .htaccess,所有规则必须写进 server 块
试图把 Apache 的 .htaccess 内容直接复制到 Nginx 配置里,必然失败。Nginx 的等效逻辑靠 try_files + rewrite 组合实现:
对设计或页面进行 WCAG 2.1 AA 无障碍审计。触发关键词:“audit accessibility”、 “check a11y”、 “is this accessible?” 或在审查设计时使用。
立即学习“PHP免费学习笔记(深入)”;
- 核心是
try_files $uri $uri/ /index.php?$query_string;:先找真实文件(如/logo.png),再找目录(/admin/),都失败才交给index.php; - 如果用
rewrite ^/article/([0-9]+)$ /article.php?id=$1 last;,必须配合location @rewrite { ... }块,且last表示内部重发请求,redirect则是 302 跳转(地址栏会变); - 注意
$query_string不等于$_GET全部 —— Nginx 不会自动解析 PATH_INFO,所以 Laravel/ThinkPHP 这类依赖PATH_INFO的框架,得用fastcgi_param PATH_INFO $fastcgi_path_info;显式传参。
正则写错导致路由冲突或 404 的典型表现
看似简单的 ^article/([0-9]+)$,实际很容易踩坑:
- 没加锚点:
article/([0-9]+)会匹配/article/123/edit,但$1只捕获123,后面/edit被丢弃,导致逻辑错乱; - 过度宽松:
^(.*)$匹配一切,若放在规则末尾还带[L],CSS/JS 图片全被重写到index.php,返回 “No input file specified” 就是这个原因; - 大小写敏感:默认区分大小写,
Article/123不会命中^article/([0-9]+)$,要加[NC]标志; - 子目录部署时漏写
RewriteBase:比如站点在example.com/blog/,规则RewriteRule ^article/([0-9]+)$ article.php?id=$1会错误拼出example.com/article.php(少了一级路径),必须加RewriteBase /blog/。
最常被忽略的一点:重写后的 PHP 脚本是否真能收到参数,取决于服务器如何把重写结果传给 PHP —— Apache 通过 QUERY_STRING 环境变量,Nginx 则靠 fastcgi_param 显式设置,两者机制不同,不能假设一致。


















