在thinkphp中统计请求耗时应在appserviceprovider的boot()中监听think\responsesend事件,用$_server['request_time_float']为起点、response::send()前取终点,并写入x-response-time响应头。

怎么在 ThinkPHP 里加请求耗时统计
直接改 AppServiceProvider 或入口文件 public/index.php,在框架启动前后打时间戳就行。ThinkPHP 6+ 的生命周期钩子足够用,别去动核心类——改了升级就炸。
常见错误是只记 microtime(true) 开始时间,却在响应发送后才取结束时间,漏掉输出缓冲、Gzip 压缩这些环节。正确做法是在 Response::send() 调用前取结束时间。
- 推荐在
app/Providers/AppServiceProvider.php的boot()里注册think\ResponseSend事件监听 - 用
$_SERVER['REQUEST_TIME_FLOAT']作起点,比手动调microtime(true)更准(避免框架加载本身耗时干扰) - 把耗时写进响应头:
$response->header('X-Response-Time', round($cost * 1000, 2) . 'ms'),方便浏览器或日志采集
DB 查询慢,怎么快速定位哪条 SQL 拖垮了接口
ThinkPHP 自带的查询日志开关开起来就行,但默认不记录执行时间,也不标出慢查询阈值——得自己补。
容易踩的坑是只看 Db::listen() 回调里的 SQL 字符串,忽略绑定参数被脱敏后看不出真实数据量;还有人把日志全打到文件,线上一并发就 IO 扛不住。
- 在
config/database.php中开启'log' => true,再加'slow_log' => 500(单位毫秒) - 重写
think\db\Connection::triggerSqlLog()方法,在日志里拼上$queryTime和$bind参数(注意别打密码字段) - 线上环境用
Monolog写到stderr或syslog,别写本地文件
Redis 缓存命中率低,是不是配置错了
不是配置错,是没意识到 ThinkPHP 的缓存驱动默认不暴露命中/未命中状态。你看到 Cache::get() 返回 null,可能是 key 不存在,也可能是过期、连接失败、序列化异常——三者处理方式完全不同。
性能影响很大:一次缓存穿透可能带崩 DB,而连接超时又会拖慢整个请求链路。别依赖 Cache::has() 判断,它本身也是一次网络调用。
- 用
think\Cache的getInfo()方法(仅 Redis 驱动支持),能拿到hits/misses计数 - 在
cache.php里给 Redis 配置加上'timeout' => 0.1(秒级),避免单次卡顿拖垮接口 - 对高频 key 加
Cache::tag(),失效时批量清理,别用通配符del cache:*——Redis 不支持,会扫全库
为什么中间件里 trace() 不生效
因为 ThinkPHP 的 trace() 是基于「应用实例」的单例,中间件执行时应用可能还没完全初始化,或者你在闭包式中间件里用了 return $next($request) 提前退出,trace 数据根本没来得及 flush。
更隐蔽的问题是:调试模式关了,trace 就静默丢弃,连 warning 都不报——你以为代码没跑,其实是被吞了。
- 确保
app_debug为true,且trace配置里'type' => 'html'或'type' => 'console'已启用 - 不要在中间件
handle()里直接调trace(),改用Log::debug()记日志,再配合Log::getLog()抽取关键段 - 如果必须用 trace,把它挪到
App::after()事件里,那里应用已完整运行完
监控不是加几个埋点就完事。真正卡点往往在 DB 连接池大小、Redis 连接复用、模板编译缓存是否开启——这些地方不看配置项具体值,光看耗时数字,永远找不到根因。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











