
本文详解如何配置 apache 的 `.htaccess` 文件,使 `/css/main.css` 等静态资源请求自动映射到 `public/css/main.css`,同时确保 mvc 路由不冲突、无重定向循环。
在基于 MVC 架构的 PHP 应用中,将 Web 可访问文件(如 CSS、JS、图片)统一置于 public/ 目录是常见且安全的做法。但若希望前端 HTML 中直接使用 而非 ,就必须借助 .htaccess 实现「透明路径重写」——即浏览器请求 /css/main.css 时,服务器内部将其指向 public/css/main.css,而 URL 地址栏保持不变。
关键挑战在于:避免重写规则间的冲突与无限重定向循环。原始配置中 RedirectMatch 与后续 RewriteRule 未做前置拦截,导致对已重写为 public/xxx 的请求再次匹配、反复重写,最终触发 500 错误或浏览器重定向失败。
以下是经过生产验证的、结构清晰且具备防御性的 .htaccess 配置(适配子目录部署场景,如 /BU/cs-602/developer-story/):
RewriteEngine On RewriteBase /BU/cs-602/developer-story/ # 1. 首页请求:/ 或 /index.* → public/index.php(终止) RewriteRule ^(\/||.*index\..*)$ public/index.php [L,QSA] # 2. 安全短路:若请求路径已含 "public/",直接放行(防止循环) RewriteRule ^(.*public\/.*)$ $1 [L,QSA] # 3. 静态资源识别:匹配非 PHP/HTML/HTM 的扩展名(如 .css, .js, .png) RewriteCond %{REQUEST_URI} \.(?!php|htm|html)[a-zA-Z0-9]+$ [NC] # → 重写为 public/ + 原路径,并终止(L) RewriteRule ^(.*)$ public/$1 [L,QSA] # 4. MVC 路由兜底:仅当请求路径不是真实文件/目录/符号链接时,交由 index.php 处理 RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-l RewriteRule ^([\w\d\s\-\_\/\%]*)$ public/index.php?p=$1 [L,QSA]
✅ 核心设计逻辑说明:
- 顺序即优先级:Apache 按从上到下执行规则,[L](Last)标志确保匹配后立即终止当前轮次,防止后续规则干扰;
- 短路防御机制:第 2 条规则显式放行所有含 public/ 的路径,彻底阻断「public/css/main.css → 再次被识别为静态资源 → 重写为 public/public/css/main.css」的死循环;
- 精准静态资源判定:使用 RewriteCond + 正则 \.(?!php|htm|html)[a-zA-Z0-9]+$ 安全排除脚本类文件,[NC] 保证大小写不敏感(.CSS 同样生效);
- 子目录兼容性:RewriteBase 确保所有相对路径重写均基于实际部署路径(如 /BU/cs-602/developer-story/),无需硬编码完整 URL。
⚠️ 注意事项:
- 确保 Apache 已启用 mod_rewrite 模块,并在虚拟主机配置中允许 .htaccess 覆盖(AllowOverride All);
- 开发阶段务必开启 Apache 错误日志(LogLevel warn rewrite:trace3),可快速定位重写循环或正则匹配失败问题;
- HTML 中资源引用保持简洁:
、 即可,无需添加 public/ 前缀; - 若需支持更多静态类型(如 .woff2, .svg),可在 RewriteCond 正则中扩展:\.(?!php|htm|html|woff2|svg)[a-zA-Z0-9]+$。
该方案已在本地开发环境(XAMPP/MAMP)及 Linux 服务器实测通过,兼顾安全性、可维护性与 MVC 架构规范,是子目录部署型 PHP 应用的标准实践之一。










