将原始响应保存为分析文件
(body []byte, reqID string)
| 1277 | |
| 1278 | // 将原始响应保存为分析文件 |
| 1279 | func saveResponseForAnalysis(body []byte, reqID string) string { |
| 1280 | diagDir := "diagnostics" |
| 1281 | os.MkdirAll(diagDir, 0755) |
| 1282 | |
| 1283 | // 保存原始响应 |
| 1284 | rawPath := filepath.Join(diagDir, fmt.Sprintf("raw_response_%s.txt", reqID)) |
| 1285 | if err := os.WriteFile(rawPath, body, 0644); err != nil { |
| 1286 | logError("[reqID:%s] 保存原始响应文件失败: %v", reqID, err) |
| 1287 | return "" |
| 1288 | } |
| 1289 | |
| 1290 | // 创建分析文件 |
| 1291 | analysisPath := filepath.Join(diagDir, fmt.Sprintf("analysis_%s.txt", reqID)) |
| 1292 | f, err := os.Create(analysisPath) |
| 1293 | if err != nil { |
| 1294 | logError("[reqID:%s] 创建分析文件失败: %v", reqID, err) |
| 1295 | return rawPath // 至少返回原始文件路径 |
| 1296 | } |
| 1297 | defer f.Close() |
| 1298 | |
| 1299 | // 写入分析头部 |
| 1300 | fmt.Fprintf(f, "WoCloud 响应分析 - 请求ID: %s\n", reqID) |
| 1301 | fmt.Fprintf(f, "分析时间: %s\n", time.Now().Format(time.RFC3339)) |
| 1302 | fmt.Fprintf(f, "原始响应大小: %d 字节\n\n", len(body)) |
| 1303 | |
| 1304 | // 解析响应行 |
| 1305 | bodyStr := string(body) |
| 1306 | lines := strings.Split(bodyStr, "\n") |
| 1307 | |
| 1308 | // 统计信息 |
| 1309 | var stats struct { |
| 1310 | TotalLines int |
| 1311 | DataLines int |
| 1312 | ValidJSON int |
| 1313 | InvalidJSON int |
| 1314 | ResponseLines int |
| 1315 | MaxResponseLength int |
| 1316 | } |
| 1317 | |
| 1318 | stats.TotalLines = len(lines) |
| 1319 | |
| 1320 | // 记录所有响应内容的长度 |
| 1321 | responseLengths := make([]int, 0) |
| 1322 | |
| 1323 | // 分析每一行 |
| 1324 | for i, line := range lines { |
| 1325 | line = strings.TrimSpace(line) |
| 1326 | if line == "" { |
| 1327 | continue |
| 1328 | } |
| 1329 | |
| 1330 | if !strings.HasPrefix(line, "data:") { |
| 1331 | fmt.Fprintf(f, "行 %d: 非data前缀行: %s\n", i+1, truncateString(line, 100)) |
| 1332 | continue |
| 1333 | } |
| 1334 | |
| 1335 | stats.DataLines++ |
| 1336 | jsonStr := strings.TrimPrefix(line, "data:") |
no test coverage detected