thinkphp 6 创建请求统计表的 migration 文件需用 php think migrate:create create_request_stats_table 生成,核心是声明 ip(string(45))、path、method、status_code、duration_ms 和 created_at(datetime,不加 usecurrent),并为高频查询字段添加索引。

ThinkPHP 6 创建请求统计表的 migration 文件怎么写
直接用 php think migrate:create create_request_stats_table 生成迁移文件后,核心是正确声明字段:必须包含请求时间、IP、路径、方法、状态码、耗时,且时间字段用 datetime() 而非 timestamp()(避免时区自动转换干扰统计)。
常见错误是把 ip 设为 string(15) ——IPv6 地址最长 39 位,应设为 string(45);还有人漏掉索引,导致按日期或路径查慢得明显。
public function change(): void
{
$this->schema->create('request_stats', function (Blueprint $table) {
$table->id();
$table->string('ip', 45)->index(); // IPv6 支持 + 查询加速
$table->string('path', 255)->index();
$table->string('method', 10)->index();
$table->smallInteger('status_code');
$table->integer('duration_ms')->unsigned(); // 毫秒级耗时,避免浮点
$table->datetime('created_at'); // 不用 useCurrent(),日志写入时显式赋值更可控
$table->index(['created_at', 'path']); // 复合索引,支撑「某天某接口」类查询
});
}
如何在中间件里记录请求数据到 stats 表
不能在控制器里手动插入——漏掉异常中断的请求;也不能用 Db::insert() 硬写,要走模型或 QueryBuilder,确保事务和连接复用。关键点是:耗时必须用 microtime(true) 前后差值,且转成整数毫秒;path 要过滤掉带参数的 URL,只留路由路径(比如 /api/user/123 → /api/user/:id),否则统计会散列。
容易踩的坑:$request->ip() 在 Nginx 反代下默认拿不到真实 IP,得配 $request->realIP() 并确认 TRUSTED_PROXY 已设;另外别在 after() 钩子里写 DB 操作,TP6 的中间件 after 是同步执行但可能已关闭数据库连接。
- 在中间件
handle()开头记 start_time - 用
App::after()或响应发送前的钩子做写入(推荐用Response::send事件监听) - 用
RequestStat::create([...])走模型,触发自动时间填充和类型转换
为什么不用日志文件而选数据库存统计
日志文件适合归档和调试,但实时聚合(比如「过去一小时每分钟 404 数量」)要靠外部工具解析,延迟高、难关联业务维度。数据库能直接 GROUP BY DATE_FORMAT(created_at, '%Y-%m-%d %H:%i'),配合定时任务跑轻量汇总表即可支撑后台图表。
不过要注意:高频写入(如每秒百次请求)会拖慢主库。实际部署时建议:
- 用单独的从库或统计专用库(配置
db_stats连接) - 批量写入:缓存 10 条再
Db::table()->insertAll(),而非每请求一次insert() - 定期归档:每月初把上月数据
INSERT INTO request_stats_hist ... SELECT后DELETE
统计表字段要不要加 soft delete 或 user_id
不加。请求统计是只追加的审计类数据,deleted_at 字段徒增索引体积和判断成本;user_id 更不能直接加——未登录用户为空,且登录态可能在中间件之后才解析,强耦合会导致写入失败或 NULL 泛滥。
真要关联用户,应在业务层记录时通过上下文提取(如从 Token 解析出 ID),并额外建宽表(如 request_stats_enhanced)异步补全,主统计表保持轻量、稳定、不可变。
最常被忽略的是 created_at 的精度和时区一致性:确保 PHP date_default_timezone_set('Asia/Shanghai') 和 MySQL 的 time_zone 都对齐,否则凌晨报表会出现跨天偏移。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











