ThinkPHP路由静态化需先关闭动态路由解析,确保Nginx直接服务HTML文件;生成时用Response::create()写入真实磁盘路径;Nginx配置try_files优先匹配静态文件;更新/删除内容时同步刷新HTML并清理CDN缓存。

ThinkPHP 路由静态化要先关掉动态路由解析
TP 默认所有请求都走 index.php 入口,哪怕你生成了 HTML 文件,Nginx 仍会把请求转发给 PHP 处理——这一步不拦住,静态化就形同虚设。
关键动作是:在 config/route.php 中关闭「强制解析」,并确保没有全局的 Route::any() 或通配符规则兜底。否则生成的 HTML 会被路由层直接拦截重定向或 404。
- 检查
config/app.php中'url_route_must' => false(不是true) - 确认
route/目录下没写类似Route::get('(.*)', 'index/index')的万能匹配 - 生成静态页前,临时禁用中间件里的 URL 自动补全、多语言跳转等干扰逻辑
用 think\template\driver\File + Response::create() 生成真实 HTML 文件
别依赖视图缓存或模板输出捕获——那些只是内存里的字符串。你要的是磁盘上可被 Nginx 直接服务的 .html 文件,且路径必须和线上 URL 完全一致(比如 /article/123.html 对应 public/article/123.html)。
实操时用 Response::create() 拿到完整渲染结果,再手动写入文件:
立即学习“PHP免费学习笔记(深入)”;
$html = Response::create('/article/123', 'view')->getContent();
file_put_contents(ROOT_PATH . 'public' . DS . 'article' . DS . '123.html', $html);
- 路径拼接必须用
ROOT_PATH . 'public',不能用__PUBLIC__或相对路径 -
/article/123是路由地址,不是模板名;确保该路由当前可正常访问(含参数绑定、模型查询) - 生成前检查目标目录权限,
public/article/需存在且 Web 用户可写
Nginx rewrite 规则要“先查文件,再回退 PHP”
静态化成败取决于 Nginx 是否真的跳过了 PHP。常见错误是写了 rewrite 却没加 -f 判断,导致所有请求仍进 index.php。
正确写法是在 server 块里加 location,优先命中真实 HTML 文件:
location / {
try_files $uri $uri/ @php;
}
location @php {
fastcgi_pass php-fpm;
include fastcgi.conf;
}
-
try_files $uri会检查$uri是否为真实文件,比如请求/article/123.html时,它会找public/article/123.html - 不要用
rewrite ^/(.*)\.html$ /index.php?s=/$1.html break;这类强行转发规则——它绕过了文件存在性判断 - 生成的 HTML 文件名必须带
.html后缀,且 URL 路径与文件系统路径严格对应(大小写、斜杠方向都不能错)
静态页更新时机比生成更难处理
内容变了,HTML 文件没更新,用户看到的就是脏数据。TP 没内置静态页生命周期管理,得自己串逻辑。
最稳的方式是在模型 afterWrite 钩子或业务操作末尾触发重建:
// 文章更新后
Article::event('after_write', function ($model) {
file_put_contents(public_path('article' . DS . $model->id . '.html'),
Response::create('/article/' . $model->id, 'view')->getContent()
);
});
- 避免在高并发编辑场景下频繁生成——加个时间戳或版本号判断是否真有变更
- 删除文章时,记得同步
unlink()对应 HTML 文件,否则残留死链 - CDN 缓存要配合
Cache-Control或主动刷新,不然用户可能卡在旧 HTML 里
真正麻烦的从来不是生成那几行代码,而是让静态文件和数据库状态始终对得上。一个没清理的旧 HTML,比没静态化还糟。











