Przeglądaj źródła

改进debug:reproduce-error命令,根据请求头智能组织请求内容

- 新增完整的请求头信息显示,包含所有HTTP请求头
- 新增请求头分析功能,自动检测Content-Type、认证方式、设备类型等
- 新增智能数据源推荐,根据请求头分析推荐最佳数据源
- 新增增强的请求数据信息显示:
  * 显示数据源、类型、大小等详细分析
  * 显示请求上下文信息(AJAX、移动设备、认证类型等)
  * 改进数据预览,支持二进制数据的文本检测
- 新增多个辅助方法:
  * displayRequestHeaders() - 显示请求头(敏感信息脱敏)
  * analyzeRequestHeaders() - 分析请求头并提取关键信息
  * determineBestDataSource() - 智能推荐数据源
  * determineDataType() - 智能检测数据类型
  * displayRequestDataInfo() - 显示增强的请求数据信息
- 更新数据准备方法,支持头部分析结果
- 通过实际测试验证所有功能正常工作
AI Assistant 6 miesięcy temu
rodzic
commit
e8dc4ed1f6

+ 203 - 0
AiWork/2025年06月/190222-debug命令响应头智能显示改进.md

@@ -0,0 +1,203 @@
+# debug:reproduce-error 命令响应头智能显示改进
+
+**时间**: 2025年06月19日 02:22:25 CST  
+**任务**: 改进 debug:reproduce-error 命令,使其能够根据返回的header来展示返回内容
+
+## 任务概述
+
+改进现有的 `debug:reproduce-error` 命令,使其能够根据HTTP响应头中的 `Content-Type` 来智能选择最合适的内容显示方式,而不是仅仅基于请求类型来决定如何显示响应。
+
+## 问题分析
+
+### 原有问题
+在原来的实现中,`displayResponse` 方法使用请求的数据类型(`$requestType`)来决定如何显示响应内容:
+
+```php
+// 原来的实现
+$this->displayResponse($response, $requestData['type']);
+
+protected function displayResponse(array $response, string $requestType): void
+{
+    if ($requestType === 'json') {
+        // 按JSON处理
+    } else {
+        // 按Protobuf处理
+    }
+}
+```
+
+这种方式存在以下问题:
+1. **逻辑错误**:请求类型不等于响应类型
+2. **显示不准确**:可能用错误的方式显示响应内容
+3. **信息缺失**:不显示响应头信息,难以调试
+4. **处理单一**:只能处理JSON和Protobuf两种类型
+
+## 改进方案
+
+### 1. 修改方法签名
+```php
+// 改进后的实现
+$this->displayResponse($response);
+
+protected function displayResponse(array $response): void
+```
+
+### 2. 新增响应头显示
+```php
+// 显示响应头信息
+$this->line("响应头:");
+foreach ($response['headers'] as $name => $values) {
+    $value = is_array($values) ? implode(', ', $values) : $values;
+    $this->line("  {$name}: {$value}");
+}
+```
+
+### 3. 智能Content-Type检测
+```php
+// 从响应头中提取Content-Type
+$responseContentType = $this->extractResponseContentType($response['headers']);
+$this->line("检测到响应Content-Type: " . ($responseContentType ?: '未知'));
+```
+
+### 4. 多种内容类型支持
+- **JSON响应** (`application/json`): 解析并格式化显示
+- **HTML响应** (`text/html`): 提取标题、内容预览、错误页面检测
+- **Protobuf响应** (`application/x-protobuf`): 显示二进制信息和Base64编码
+- **文本响应** (`text/*`): 直接显示内容
+- **未知类型**: 智能检测并选择最佳显示方式
+
+## 实现细节
+
+### 1. Content-Type提取方法
+```php
+protected function extractResponseContentType(array $headers): ?string
+{
+    // 支持不同的大小写变体
+    $contentTypeKeys = ['Content-Type', 'content-type', 'Content-type', 'CONTENT-TYPE'];
+    
+    foreach ($contentTypeKeys as $key) {
+        if (isset($headers[$key])) {
+            $value = is_array($headers[$key]) ? $headers[$key][0] : $headers[$key];
+            // 只取分号前的部分(去掉charset等参数)
+            return trim(explode(';', $value)[0]);
+        }
+    }
+    
+    return null;
+}
+```
+
+### 2. 类型检测方法
+```php
+protected function isJsonContentType(?string $contentType): bool
+protected function isProtobufContentType(?string $contentType): bool
+protected function isHtmlContentType(?string $contentType): bool
+protected function isTextContentType(?string $contentType): bool
+```
+
+### 3. 专门的显示方法
+```php
+protected function displayHtmlContent(string $content): void
+protected function displayRawContent(string $content): void
+protected function smartDisplayContent(string $content): void
+```
+
+## 测试验证
+
+### 测试用例1:JSON响应
+```
+状态码: 500
+响应头:
+  Server: nginx/1.27.5
+  Content-Type: application/json
+检测到响应Content-Type: application/json
+响应体长度: 10165 字节
+按JSON格式解析响应:
+array:5 [
+  "message" => "Malformed UTF-8 characters, possibly incorrectly encoded"
+  "exception" => "InvalidArgumentException"
+  ...
+]
+```
+
+### 测试用例2:HTML响应
+```
+状态码: 200
+响应头:
+  Server: nginx/1.27.5
+  Content-Type: text/html; charset=UTF-8
+检测到响应Content-Type: text/html
+响应体长度: 289492 字节
+按HTML格式处理响应:
+HTML页面标题: KU-K
+HTML内容预览: Sfdump = window.Sfdump || (function (doc) { ...
+检测到可能的错误页面
+```
+
+### 测试用例3:Protobuf响应
+```
+状态码: 200
+响应头:
+  Content-Type: application/x-protobuf
+检测到响应Content-Type: application/x-protobuf
+按Protobuf格式处理响应:
+Base64 编码: CgR0ZXN0EAEYAiIGaGVsbG8=...
+响应为二进制 Protobuf 数据,无法直接显示
+```
+
+## 改进效果
+
+### 1. 功能增强
+- ✅ 显示完整的响应头信息,便于调试
+- ✅ 根据实际响应Content-Type智能选择显示方式
+- ✅ 支持多种内容类型:JSON、HTML、Protobuf、文本等
+- ✅ 智能检测未知类型并选择最佳显示方式
+
+### 2. 调试体验提升
+- ✅ 更详细的响应信息展示
+- ✅ 错误页面自动检测
+- ✅ HTML内容结构化显示
+- ✅ 二进制数据安全显示
+
+### 3. 兼容性保持
+- ✅ 保持原有命令参数和选项不变
+- ✅ 向后兼容所有现有功能
+- ✅ 不影响现有的请求重放逻辑
+
+## 技术亮点
+
+1. **智能检测**:根据响应头而非请求类型决定显示方式
+2. **多格式支持**:支持JSON、HTML、Protobuf、文本等多种格式
+3. **错误检测**:自动检测HTML错误页面
+4. **安全显示**:二进制数据使用Base64编码安全显示
+5. **用户友好**:提供清晰的格式化输出和内容预览
+
+## 文件修改
+
+### 主要修改
+- `app/Console/Commands/ReproduceErrorCommand.php`
+  - 修改 `displayResponse` 方法签名和实现
+  - 新增多个Content-Type检测方法
+  - 新增多个专门的内容显示方法
+  - 更新命令描述和帮助信息
+
+### 新增方法
+- `extractResponseContentType()` - 提取响应Content-Type
+- `isJsonContentType()` - 检测JSON类型
+- `isProtobufContentType()` - 检测Protobuf类型
+- `isHtmlContentType()` - 检测HTML类型
+- `isTextContentType()` - 检测文本类型
+- `displayHtmlContent()` - 显示HTML内容
+- `displayRawContent()` - 显示原始内容
+- `smartDisplayContent()` - 智能显示内容
+
+## 总结
+
+此次改进大幅提升了 `debug:reproduce-error` 命令的实用性和用户体验:
+
+1. **解决了核心问题**:使用响应头而非请求类型来决定显示方式
+2. **增强了调试能力**:显示完整响应头信息,便于问题排查
+3. **提升了智能化**:支持多种内容类型的智能识别和显示
+4. **改善了用户体验**:提供更清晰、更有用的输出格式
+
+这些改进使得命令在实际调试工作中更加有用和高效。

+ 399 - 49
app/Console/Commands/ReproduceErrorCommand.php

@@ -100,18 +100,14 @@ class ReproduceErrorCommand extends Command
         $this->line("  方法: {$requestLog->method}");
         $this->line("  创建时间: {$requestLog->created_at}");
 
-        // 解析 headers 获取 Content-Type 和 token
+        // 解析并显示请求头信息
         $headers = $this->parseHeaders($requestLog->headers);
+        $this->displayRequestHeaders($headers);
+
+        // 提取关键信息
         $contentType = $this->extractContentType($headers);
         $token = $this->extractToken($requestLog->headers);
-
-        $this->info("Content-Type: " . ($contentType ?: '未检测到'));
-
-        if (!$token) {
-            $this->warn("未找到 token,将不携带 token 发起请求");
-        } else {
-            $this->info("提取到 token: " . substr($token, 0, 10) . "...");
-        }
+        $headerAnalysis = $this->analyzeRequestHeaders($headers);
 
         // 设置用户会话
         if ($requestLog->user_id) {
@@ -119,21 +115,13 @@ class ReproduceErrorCommand extends Command
             $this->info("token 设置用户: {$requestLog->user_id} ");
         }
 
-        // 准备请求数据
-        $requestData = $this->prepareRequestData($requestLog, $dataSource, $contentType);
+        // 准备请求数据(使用头部分析结果)
+        $requestData = $this->prepareRequestData($requestLog, $dataSource, $contentType, $headerAnalysis);
         if ($requestData === null) {
             return 1;
         }
 
-        $this->info("使用数据源: {$requestData['source']}");
-        $this->info("检测到数据类型: {$requestData['type']}");
-        $this->info("请求数据预览:");
-        if ($requestData['type'] === 'json') {
-            dump(json_decode($requestData['data'], true));
-        } else {
-            $this->line("  二进制数据长度: " . strlen($requestData['data']) . " 字节");
-            $this->line("  Base64预览: " . substr(base64_encode($requestData['data']), 0, 100) . "...");
-        }
+        $this->displayRequestDataInfo($requestData);
 
         // 初始化 HTTP 客户端
         $this->initializeHttpClient($timeout);
@@ -204,6 +192,164 @@ class ReproduceErrorCommand extends Command
         }
     }
 
+    /**
+     * 显示请求头信息
+     *
+     * @param array $headers 解析后的请求头数组
+     */
+    protected function displayRequestHeaders(array $headers): void
+    {
+        if (empty($headers)) {
+            $this->warn("未找到请求头信息");
+            return;
+        }
+
+        $this->info("请求头信息:");
+        foreach ($headers as $name => $values) {
+            $value = is_array($values) ? implode(', ', $values) : $values;
+
+            // 对敏感信息进行脱敏处理
+            if (in_array(strtolower($name), ['token', 'authorization', 'cookie'])) {
+                if (strlen($value) > 10) {
+                    $value = substr($value, 0, 10) . '...(已脱敏)';
+                }
+            }
+
+            $this->line("  {$name}: {$value}");
+        }
+    }
+
+    /**
+     * 分析请求头信息
+     *
+     * @param array $headers 解析后的请求头数组
+     * @return array 分析结果
+     */
+    protected function analyzeRequestHeaders(array $headers): array
+    {
+        $analysis = [
+            'content_type' => null,
+            'content_length' => null,
+            'user_agent' => null,
+            'accept' => null,
+            'encoding' => null,
+            'auth_type' => null,
+            'is_ajax' => false,
+            'is_mobile' => false,
+            'has_custom_headers' => false,
+            'security_headers' => [],
+            'custom_headers' => []
+        ];
+
+        foreach ($headers as $name => $values) {
+            $value = is_array($values) ? ($values[0] ?? '') : $values;
+            $lowerName = strtolower($name);
+
+            switch ($lowerName) {
+                case 'content-type':
+                    $analysis['content_type'] = $value;
+                    if (str_contains($value, 'charset=')) {
+                        $analysis['encoding'] = trim(explode('charset=', $value)[1]);
+                    }
+                    break;
+                case 'content-length':
+                    $analysis['content_length'] = (int)$value;
+                    break;
+                case 'user-agent':
+                    $analysis['user_agent'] = $value;
+                    $analysis['is_mobile'] = $this->isMobileUserAgent($value);
+                    break;
+                case 'accept':
+                    $analysis['accept'] = $value;
+                    break;
+                case 'authorization':
+                    $analysis['auth_type'] = 'Bearer/Basic';
+                    break;
+                case 'token':
+                    $analysis['auth_type'] = 'Token';
+                    break;
+                case 'x-requested-with':
+                    if (strtolower($value) === 'xmlhttprequest') {
+                        $analysis['is_ajax'] = true;
+                    }
+                    break;
+                default:
+                    // 检测自定义头部
+                    if (str_starts_with($lowerName, 'x-') ||
+                        !in_array($lowerName, ['host', 'connection', 'cache-control', 'pragma', 'accept-encoding', 'accept-language'])) {
+                        $analysis['has_custom_headers'] = true;
+                        $analysis['custom_headers'][$name] = $value;
+                    }
+
+                    // 检测安全相关头部
+                    if (in_array($lowerName, ['x-csrf-token', 'x-xsrf-token', 'x-frame-options', 'x-content-type-options'])) {
+                        $analysis['security_headers'][$name] = $value;
+                    }
+                    break;
+            }
+        }
+
+        $this->displayHeaderAnalysis($analysis);
+        return $analysis;
+    }
+
+    /**
+     * 显示请求头分析结果
+     *
+     * @param array $analysis 分析结果
+     */
+    protected function displayHeaderAnalysis(array $analysis): void
+    {
+        $this->info("请求头分析:");
+
+        if ($analysis['content_type']) {
+            $this->line("  Content-Type: {$analysis['content_type']}");
+        }
+
+        if ($analysis['content_length']) {
+            $this->line("  Content-Length: {$analysis['content_length']} 字节");
+        }
+
+        if ($analysis['auth_type']) {
+            $this->line("  认证方式: {$analysis['auth_type']}");
+        }
+
+        if ($analysis['is_ajax']) {
+            $this->line("  请求类型: AJAX请求");
+        }
+
+        if ($analysis['is_mobile']) {
+            $this->line("  客户端: 移动设备");
+        }
+
+        if ($analysis['has_custom_headers']) {
+            $this->line("  自定义头部: " . count($analysis['custom_headers']) . " 个");
+        }
+
+        if (!empty($analysis['security_headers'])) {
+            $this->line("  安全头部: " . implode(', ', array_keys($analysis['security_headers'])));
+        }
+    }
+
+    /**
+     * 检测是否为移动设备User-Agent
+     *
+     * @param string $userAgent
+     * @return bool
+     */
+    protected function isMobileUserAgent(string $userAgent): bool
+    {
+        $mobileKeywords = ['Mobile', 'Android', 'iPhone', 'iPad', 'Windows Phone', 'BlackBerry'];
+
+        foreach ($mobileKeywords as $keyword) {
+            if (str_contains($userAgent, $keyword)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     /**
      * 解析 headers JSON 字符串
      *
@@ -283,82 +429,286 @@ class ReproduceErrorCommand extends Command
      * @param RequestLog $requestLog
      * @param string $dataSource
      * @param string|null $contentType
+     * @param array $headerAnalysis
      * @return array|null
      */
-    protected function prepareRequestData(RequestLog $requestLog, string $dataSource, ?string $contentType): ?array
+    protected function prepareRequestData(RequestLog $requestLog, string $dataSource, ?string $contentType, array $headerAnalysis = []): ?array
     {
-        // 根据数据源选择策略
+        // 根据数据源选择策略,结合头部分析结果
         if ($dataSource === 'auto') {
-            // 自动选择:优先使用 post 数据,如果没有则使用 protobuf_json
-            if (!empty($requestLog->post)) {
-                return $this->preparePostData($requestLog->post, $contentType);
-            } elseif (!empty($requestLog->protobuf_json)) {
-                return $this->prepareProtobufJsonData($requestLog->protobuf_json);
+            // 智能选择:根据头部分析结果决定最佳数据源
+            $bestSource = $this->determineBestDataSource($requestLog, $headerAnalysis);
+            $this->info("根据请求头分析,推荐使用数据源: {$bestSource}");
+
+            if ($bestSource === 'post' && !empty($requestLog->post)) {
+                return $this->preparePostData($requestLog->post, $contentType, $headerAnalysis);
+            } elseif ($bestSource === 'protobuf_json' && !empty($requestLog->protobuf_json)) {
+                return $this->prepareProtobufJsonData($requestLog->protobuf_json, $headerAnalysis);
             } else {
-                $this->error("请求记录中既没有 post 数据也没有 protobuf_json 数据");
-                return null;
+                // 回退到原有逻辑
+                if (!empty($requestLog->post)) {
+                    return $this->preparePostData($requestLog->post, $contentType, $headerAnalysis);
+                } elseif (!empty($requestLog->protobuf_json)) {
+                    return $this->prepareProtobufJsonData($requestLog->protobuf_json, $headerAnalysis);
+                } else {
+                    $this->error("请求记录中既没有 post 数据也没有 protobuf_json 数据");
+                    return null;
+                }
             }
         } elseif ($dataSource === 'post') {
             if (empty($requestLog->post)) {
                 $this->error("请求记录中缺少 post 数据");
                 return null;
             }
-            return $this->preparePostData($requestLog->post, $contentType);
+            return $this->preparePostData($requestLog->post, $contentType, $headerAnalysis);
         } elseif ($dataSource === 'protobuf_json') {
             if (empty($requestLog->protobuf_json)) {
                 $this->error("请求记录中缺少 protobuf_json 数据");
                 return null;
             }
-            return $this->prepareProtobufJsonData($requestLog->protobuf_json);
+            return $this->prepareProtobufJsonData($requestLog->protobuf_json, $headerAnalysis);
         } else {
             $this->error("不支持的数据源: {$dataSource}");
             return null;
         }
     }
 
+    /**
+     * 根据请求头分析确定最佳数据源
+     *
+     * @param RequestLog $requestLog
+     * @param array $headerAnalysis
+     * @return string
+     */
+    protected function determineBestDataSource(RequestLog $requestLog, array $headerAnalysis): string
+    {
+        // 如果Content-Type明确指示JSON,优先使用protobuf_json
+        if ($headerAnalysis['content_type'] &&
+            str_contains(strtolower($headerAnalysis['content_type']), 'json')) {
+            return 'protobuf_json';
+        }
+
+        // 如果Content-Type指示protobuf或二进制,优先使用post
+        if ($headerAnalysis['content_type'] &&
+            (str_contains(strtolower($headerAnalysis['content_type']), 'protobuf') ||
+             str_contains(strtolower($headerAnalysis['content_type']), 'octet-stream'))) {
+            return 'post';
+        }
+
+        // 如果是AJAX请求,通常是JSON格式
+        if ($headerAnalysis['is_ajax']) {
+            return 'protobuf_json';
+        }
+
+        // 默认优先使用post数据
+        return 'post';
+    }
+
     /**
      * 准备 post 数据
      *
      * @param string $postData base64 编码的原始请求数据
      * @param string|null $contentType
+     * @param array $headerAnalysis
      * @return array
      */
-    protected function preparePostData(string $postData, ?string $contentType): array
+    protected function preparePostData(string $postData, ?string $contentType, array $headerAnalysis = []): array
     {
         // 解码 base64 数据
         $rawData = base64_decode($postData);
 
-        // 根据 Content-Type 判断数据类型
-        if ($contentType && stripos($contentType, 'json') !== false) {
-            // JSON 格式数据
-            return [
-                'source' => 'post',
-                'type' => 'json',
-                'data' => $rawData
-            ];
-        } else {
-            // 默认为 protobuf 二进制格式
-            return [
-                'source' => 'post',
-                'type' => 'protobuf',
-                'data' => $rawData
+        // 根据请求头分析和 Content-Type 判断数据类型
+        $dataType = $this->determineDataType($contentType, $headerAnalysis, $rawData);
+
+        $result = [
+            'source' => 'post',
+            'type' => $dataType,
+            'data' => $rawData,
+            'analysis' => [
+                'original_size' => strlen($postData),
+                'decoded_size' => strlen($rawData),
+                'content_type' => $contentType,
+                'detected_type' => $dataType
+            ]
+        ];
+
+        // 如果有头部分析信息,添加到结果中
+        if (!empty($headerAnalysis)) {
+            $result['header_context'] = [
+                'is_ajax' => $headerAnalysis['is_ajax'] ?? false,
+                'is_mobile' => $headerAnalysis['is_mobile'] ?? false,
+                'auth_type' => $headerAnalysis['auth_type'] ?? null,
+                'content_length' => $headerAnalysis['content_length'] ?? null
             ];
         }
+
+        return $result;
+    }
+
+    /**
+     * 确定数据类型
+     *
+     * @param string|null $contentType
+     * @param array $headerAnalysis
+     * @param string $rawData
+     * @return string
+     */
+    protected function determineDataType(?string $contentType, array $headerAnalysis, string $rawData): string
+    {
+        // 优先根据Content-Type判断
+        if ($contentType) {
+            if (stripos($contentType, 'json') !== false) {
+                return 'json';
+            }
+            if (stripos($contentType, 'protobuf') !== false ||
+                stripos($contentType, 'octet-stream') !== false) {
+                return 'protobuf';
+            }
+        }
+
+        // 根据请求头分析判断
+        if (!empty($headerAnalysis['is_ajax'])) {
+            return 'json';
+        }
+
+        // 尝试解析数据内容判断
+        if ($this->looksLikeJson($rawData)) {
+            return 'json';
+        }
+
+        // 默认为protobuf
+        return 'protobuf';
+    }
+
+    /**
+     * 检查数据是否看起来像JSON
+     *
+     * @param string $data
+     * @return bool
+     */
+    protected function looksLikeJson(string $data): bool
+    {
+        // 检查是否以JSON常见字符开始
+        $trimmed = trim($data);
+        if (empty($trimmed)) {
+            return false;
+        }
+
+        $firstChar = $trimmed[0];
+        if (in_array($firstChar, ['{', '[', '"'])) {
+            // 尝试解析JSON
+            json_decode($trimmed);
+            return json_last_error() === JSON_ERROR_NONE;
+        }
+
+        return false;
     }
 
     /**
      * 准备 protobuf_json 数据
      *
      * @param string $protobufJson
+     * @param array $headerAnalysis
      * @return array
      */
-    protected function prepareProtobufJsonData(string $protobufJson): array
+    protected function prepareProtobufJsonData(string $protobufJson, array $headerAnalysis = []): array
     {
-        return [
+        $result = [
             'source' => 'protobuf_json',
             'type' => 'json',
-            'data' => $protobufJson
+            'data' => $protobufJson,
+            'analysis' => [
+                'data_size' => strlen($protobufJson),
+                'detected_type' => 'json'
+            ]
         ];
+
+        // 如果有头部分析信息,添加到结果中
+        if (!empty($headerAnalysis)) {
+            $result['header_context'] = [
+                'is_ajax' => $headerAnalysis['is_ajax'] ?? false,
+                'is_mobile' => $headerAnalysis['is_mobile'] ?? false,
+                'auth_type' => $headerAnalysis['auth_type'] ?? null
+            ];
+        }
+
+        return $result;
+    }
+
+    /**
+     * 显示请求数据信息
+     *
+     * @param array $requestData
+     */
+    protected function displayRequestDataInfo(array $requestData): void
+    {
+        $this->info("请求数据信息:");
+        $this->line("  数据源: {$requestData['source']}");
+        $this->line("  数据类型: {$requestData['type']}");
+
+        // 显示分析信息
+        if (isset($requestData['analysis'])) {
+            $analysis = $requestData['analysis'];
+            $this->line("  数据分析:");
+
+            if (isset($analysis['decoded_size'])) {
+                $this->line("    原始大小: {$analysis['original_size']} 字节");
+                $this->line("    解码后大小: {$analysis['decoded_size']} 字节");
+            } elseif (isset($analysis['data_size'])) {
+                $this->line("    数据大小: {$analysis['data_size']} 字节");
+            }
+
+            if (isset($analysis['content_type'])) {
+                $this->line("    Content-Type: {$analysis['content_type']}");
+            }
+
+            if (isset($analysis['detected_type'])) {
+                $this->line("    检测类型: {$analysis['detected_type']}");
+            }
+        }
+
+        // 显示头部上下文信息
+        if (isset($requestData['header_context'])) {
+            $context = $requestData['header_context'];
+            $contextInfo = [];
+
+            if ($context['is_ajax']) {
+                $contextInfo[] = 'AJAX请求';
+            }
+            if ($context['is_mobile']) {
+                $contextInfo[] = '移动设备';
+            }
+            if ($context['auth_type']) {
+                $contextInfo[] = "认证: {$context['auth_type']}";
+            }
+
+            if (!empty($contextInfo)) {
+                $this->line("  请求上下文: " . implode(', ', $contextInfo));
+            }
+        }
+
+        // 显示数据预览
+        $this->info("请求数据预览:");
+        if ($requestData['type'] === 'json') {
+            $jsonData = json_decode($requestData['data'], true);
+            if ($jsonData !== null) {
+                dump($jsonData);
+            } else {
+                $this->warn("数据类型标记为JSON但解析失败");
+                $this->line("原始数据: " . substr($requestData['data'], 0, 200) . "...");
+            }
+        } else {
+            $this->line("  二进制数据长度: " . strlen($requestData['data']) . " 字节");
+            $this->line("  Base64预览: " . substr(base64_encode($requestData['data']), 0, 100) . "...");
+
+            // 尝试检测是否包含可读文本
+            if (mb_check_encoding($requestData['data'], 'UTF-8')) {
+                $preview = substr($requestData['data'], 0, 100);
+                if (ctype_print($preview)) {
+                    $this->line("  文本预览: {$preview}...");
+                }
+            }
+        }
     }
 
     /**