attributes->set('start_time', microtime(true)); return $next($request); } // 响应发送给客户端后执行 public function terminate(Request $request, Response $response): void { $startTime = $request->attributes->get('start_time'); $endTime = microtime(true); // 收集日志数据 $data = [ 'method' => $request->method(), 'url' => $request->fullUrl(), 'ip' => $request->ip(), 'headers' => json_encode($this->getLoggableHeaders($request), JSON_UNESCAPED_UNICODE), 'input' => $this->truncate(json_encode($request->all(), JSON_UNESCAPED_UNICODE), 5000), // 这里应用截断逻辑:如果 response 超过 10KB,将直接存储 'Data too long for column' 'response' => $this->truncate((string) $response->getContent(), 10000), 'status_code' => $response->status(), 'response_time' => round($endTime - $startTime, 3), 'created_at' => now(), 'updated_at' => now() ]; $tableName = 'zz_request_' . date('Ym'); $this->createTableIfNotExists($tableName); DB::table($tableName)->insert($data); } /** * 检查并创建月度表 */ protected function createTableIfNotExists($tableName) { if (!Schema::hasTable($tableName)) { // 使用 Schema 构建器创建表 Schema::create($tableName, function (Blueprint $table) { $table->increments('id'); $table->string('method', 10)->comment('请求方法'); $table->text('url')->comment('请求URL'); $table->string('ip', 45)->comment('客户端IP'); $table->text('headers')->nullable()->comment('请求头'); $table->text('input')->nullable()->comment('请求参数'); $table->text('response'); $table->integer('status_code')->comment('响应状态码'); $table->decimal('response_time', 10, 3)->comment('响应时间(毫秒)'); $table->timestamps(); $table->index('created_at', 'idx_created_at'); }); } } /** * 简单的长度检查:要么全要,要么给个提示 * 不再进行复杂的截断操作 */ protected function truncate($string, $maxBytes = 5000) { // 如果长度没超标,直接返回原数据 if (strlen($string) <= $maxBytes) { return $string; } // 如果超标了,直接返回一个固定的提示字符串 return 'Data too long for column'; } protected function getLoggableHeaders(Request $request) { $whitelist = [ 'authorization', 'content-type', 'user-agent', 'x-requested-with', 'x-forwarded-for', 'x-real-ip', 'x-correlation-id', 'trace-id', 'request-id', 'host' ]; $result = []; foreach ($whitelist as $header) { if (!$request->headers->has($header)) { continue; } $value = $request->headers->get($header); // 脱敏处理 if (in_array(strtolower($header), ['authorization', 'cookie'])) { $result[$header] = '[' . strtoupper(substr($header, 0, 3)) . ']'; } // 或者更精细控制 elseif (strtolower($header) === 'authorization' && str_starts_with($value, 'Bearer ')) { $token = substr($value, 7); $result[$header] = 'Bearer ' . substr($token, 0, 6) . '...' . substr($token, -4); } else { $result[$header] = mb_strlen($value) > 200 ? substr($value, 0, 197) . '...' : $value; } } return $result; } }