ThinkPHP部署到子路径需全链路适配:Web服务器指向public目录并正确映射子路径;入口文件显式定义APP_BASE_PATH;配置base_url和app_url;静态资源路径统一加前缀;清理runtime缓存并验证。

ThinkPHP项目部署到子路径(比如 https://example.com/myapp/),本质不是靠框架“创建虚拟目录”,而是让整个请求链路——从Web服务器、入口文件、路由生成到静态资源引用——都统一识别并适配这个子路径前缀。核心在于:框架必须知道自己不在网站根目录,而是在一个子路径下运行。
Web服务器必须指向 public 目录,并正确映射子路径
这是前提,否则敏感文件暴露、路由全 404。不能把整个项目放子目录后就直接访问,必须让服务器只认 public/ 为 Web 可访问起点。
-
Apache:在虚拟主机配置中,
DocumentRoot和对应的<directory></directory>都要指向/var/www/html/myapp/public;同时启用AllowOverride All,确保.htaccess生效 -
Nginx:推荐用
alias方式(比root更稳妥)。例如:location /myapp/ { alias /var/www/html/myapp/public/; try_files $uri $uri/ /myapp/index.php?$query_string; } location ~ ^/myapp/(.+\.php)$ { alias /var/www/html/myapp/public/$1; fastcgi_pass unix:/run/php/php8.1-fpm.sock; fastcgi_param SCRIPT_FILENAME $request_filename; include fastcgi_params; }注意alias和$request_filename的路径结尾斜杠必须一致,否则 PHP 找不到入口文件
入口文件需手动声明子路径基准
ThinkPHP 默认靠 $_SERVER['SCRIPT_NAME'] 推导 URL 基础路径,但在子路径 + 重写环境下常出错。最可靠方式是显式定义:
- 在
public/index.php开头(require __DIR__.'/../vendor/autoload.php';之前)加入:define('APP_BASE_PATH', '/myapp/'); - 然后在
config/app.php中配置:'app_url' => 'https://example.com/myapp',<br>'base_url' => APP_BASE_PATH,
- 这样
url('index/index')才会生成/myapp/index/index,而不是漏掉前缀
静态资源路径必须带子路径前缀
浏览器请求 /static/js/app.js,实际文件却在 /myapp/public/static/js/app.js,所以所有 CSS/JS/IMG 链接都要补上前缀。
立即学习“PHP免费学习笔记(深入)”;
- 不改服务器时,硬编码最直接:
<link rel="stylesheet" href="/myapp/static/css/app.css"> - 使用模板变量替换(TP6 支持):
在config/view.php中设置:'replace' => [ '__STATIC__' => '/myapp/static', '__CSS__' => '/myapp/static/css' ] - 切记检查 CSS 里的
background: url(../img/logo.png)这类相对路径,它们也会因子路径失效,建议统一用绝对路径前缀
部署后必须清理缓存并验证路径逻辑
旧缓存里存的是根路径下的路径推导结果,不清理会导致各种 404 和权限错误。
- 删掉
runtime/目录,让框架重建缓存 - 确认
public/index.php开头有chdir(dirname(__DIR__));,保证工作目录是项目根,避免命令行或子目录部署时路径偏移 - 运行
php think optimize:config生成新配置缓存,再测试几个关键页面和接口 - 检查 Nginx/Apache 错误日志,看是否有
Permission denied(目录缺少执行权限)或File not found(SCRIPT_FILENAME拼错)



















