根本原因是Web服务器未以public目录为文档根,导致/static/js/app.js等请求被直接映射到错误物理路径而404;需将Apache的DocumentRoot或Nginx的root指向public目录,并在强制路由开启时用Route::rule()显式放行静态资源后缀。

静态资源(css、js、img)在 ThinkPHP5.1 中 404,根本原因不是路径写错或文件没放对,而是 Web 服务器把 /static/js/app.js 当作真实文件路径去磁盘查找,而没意识到它该由 PHP 路由接管——或者更常见的是:你把整个项目放到了子目录,但 public 没被设为 Web 根目录。
为什么浏览器请求 /static/js/app.js 却返回 404
ThinkPHP5.1 默认要求 Web 服务器以 public 目录为文档根(Document Root)。如果你把项目解压到 /var/www/html/myapp/,却让 Nginx/Apache 的 root 指向 /var/www/html/,那么:
- 浏览器请求
/static/js/app.js - 服务器在
/var/www/html/static/js/app.js找,而不是/var/www/html/myapp/public/static/js/app.js - 文件不存在 → 404,ThinkPHP 压根没启动
验证方法:直接访问 http://your-domain.com/public/static/js/app.js,如果能打开,就坐实了这个问题。
Apache 下如何正确配置 DocumentRoot 和 .htaccess
Apache 环境下必须确保两点同时成立:
立即学习“PHP免费学习笔记(深入)”;
-
DocumentRoot必须指向项目的public目录,例如/var/www/html/myapp/public -
.htaccess文件必须启用且内容有效(TP5.1 自带的即可,无需修改) - 确认 Apache 已开启
mod_rewrite,并允许AllowOverride All(否则 .htaccess 不生效)
常见错误:把 DocumentRoot 设为项目根目录(/myapp),然后靠 .htaccess 重写跳转——这会导致所有静态资源路径自动带上 /myapp/ 前缀,而你代码里没写,结果还是 404。
Nginx 下 public 目录未设为 root 的典型表现
Nginx 不读 .htaccess,全靠配置。若你用宝塔或手动配错,会出现:
- 首页能打开(因为
/被 rewrite 到/index.php,而入口存在) - 但
/static/css/app.css404(Nginx 直接找物理路径,没转发给 PHP) -
location /块里缺try_files $uri $uri/ /index.php?$query_string; - 或更隐蔽的问题:
root指向了项目根,而非public;此时必须显式改写静态资源路径:location ^~ /static/ { alias /var/www/html/myapp/public/static/; }
注意:alias 结尾必须有 /,且路径要绝对;用 root 时,末尾不加 /,语义完全不同。
强制路由模式下静态资源被误匹配
如果你开了 'url_route_must' => true(强制路由),ThinkPHP5.1 会把所有请求(包括 /static/xxx)都扔进路由系统匹配。由于没定义对应规则,全部 404。
解决方式是在 route/route.php 最顶部加一条放行规则:
Route::rule(':path^.*\.(js|css|png|jpg|gif|svg|woff2|ttf)$', 'static/:path', 'GET', ['ext' => '']);
这条规则的意思是:只要 URL 后缀是这些类型,就直接映射到 public/static/ 下的真实文件,不走控制器。别漏掉 ['ext' => ''],否则 ThinkPHP 会强行补上 .html 后缀导致失败。
真正卡住人的地方,往往不是框架本身,而是 Web 服务器是否真的把 public 当成了起点。哪怕只差一层目录,所有静态资源都会静默失效——而且错误现象和「路径写错」一模一样,容易反复检查 HTML 里的 src 却忽略服务器配置。



















