🔧 API接口文档 v3.0.2

MC部落日志分析器 - 企业级安全的高性能WebAPI

📋 接口概览

所有API基于RESTful设计,使用JSON格式交互。Base URL: https://mclans.sakurain.net

🚀 v3.0 新特性

  • ✨ 增强内容验证引擎,防止伪装日志文件
  • 🔒 集成SQLite审计日志系统,完整行为追踪
  • 📦 任务级文件隔离,上传目录按任务ID划分
  • 🔄 智能WebSocket重连机制,实时推送更稳定
  • ⚡ Windows平台内存解压优化,解决文件锁定问题
  • 🎯 Shop模式支持商品交易次数精确统计
  • 📊 PvP模式增强时间戳提取,支持从文件名获取日期

🛡️ 安全特性

所有接口内置企业级安全防护,包括:

  • 🚦 速率限制:上传50次/小时,分析20次/小时
  • 📊 内容验证:采样检测日志格式(≥15%特征率)+ 熵值检测(≤7.5)
  • 🔍 压缩炸弹防护:最大压缩比1000倍,解压后5GB软限制
  • 🎯 灰名单监控:自动记录可疑IP行为,超过阈值加强监控
  • 📁 路径遍历防护:严格验证文件路径,阻止非法访问
  • 🛡️ 任务隔离:每个任务独立目录,防止文件交叉访问

🔑 认证说明

当前版本API为内部使用,无需认证。后续版本将添加API Key机制。

注意:所有接口受全局速率限制,超限将返回429状态码并记录到审计日志。
POST

/api/upload

功能描述:上传日志文件,支持多文件批量上传和 .gz 压缩格式。

⚠️ 安全检查流程

  1. 验证速率限制(上传行为)
  2. 检查总大小(500MB限制)
  3. 验证单个文件大小(100MB限制)
  4. 验证文件扩展名(.log, .gz)
  5. 内存解压(Windows优化)或安全解压到临时目录
  6. 严格内容验证(格式采样+熵值检测+二进制签名检查)
  7. 记录审计日志(upload事件)

请求参数

参数名 类型 必填 限制 说明
files File[] (multipart/form-data) 总大小 ≤ 500MB
单文件 ≤ 100MB
扩展名: .log, .gz
日志文件数组,支持Minecraft客户端日志

成功响应(201 Created)

{ "task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "uploaded_files": [ { "original_name": "pvp_logs_2025-01-10.log", "safe_name": "a1b2c3d4e5f6_pvp_logs_2025-01-10.log", "path": "/web_uploads/a1b2c3d4-e5f6-7890-abcd-ef1234567890/a1b2c3d4e5f6_pvp_logs_2025-01-10.log", "size": 1048576, "is_gz": false }, { "original_name": "shop_logs.log.gz", "safe_name": "b2c3d4e5f6a7_shop_logs.log", "path": "/web_uploads/a1b2c3d4-e5f6-7890-abcd-ef1234567890/b2c3d4e5f6a7_shop_logs.log", "size": 2097152, "is_gz": true } ], "file_count": 2, "total_size": 3145728, "upload_dir": "/web_uploads/a1b2c3d4-e5f6-7890-abcd-ef1234567890" }

错误响应

400 Bad Request 文件验证失败 内容格式不匹配(MC特征率<15%)、熵值>7.5、二进制文件
413 Payload Too Large 大小超限 总大小超过500MB或单文件超过100MB
429 Too Many Requests 速率限制 上传频率超过50次/小时,灰名单计数+1
POST

/api/analyze/{task_id}

功能描述:启动指定任务的分析流程,后台异步处理,最大支持3个并发任务。

路径参数

task_id string UUID格式,上传接口返回的任务唯一标识

表单参数

参数名 类型 可选值 默认值 说明
mode string pvp, shop - 分析模式:PvP击杀记录或商会交易
output_format string pvp: xlsx, pdf, png
shop: json, pdf, png, xlsx
- 输出文件格式,根据模式自动验证

成功响应(200 OK)

{ "task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "status": "任务已提交,正在后台处理", "concurrent_tasks": "当前队列位置: 1/3" }

处理流程(WebSocket推送5个阶段)

  1. 验证速率限制(分析行为)
  2. 检查任务目录和文件是否存在
  3. 创建后台分析任务(受MAX_CONCURRENT_TASKS=3限制)
  4. 加载日志 → 解析事件 → 去重处理 → 统计计算 → 导出文件
  5. WebSocket推送实时进度(每阶段更新)
  6. 完成后记录audit日志(analyze事件)
GET

/api/status/{task_id}

功能描述:查询指定任务的实时状态和进度,支持轮询或WebSocket替代方案。

路径参数

task_id string UUID格式,任务唯一标识

响应示例(处理中)

{ "task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "status": "processing", "mode": "pvp", "format": "xlsx", "progress": "65% - 正在统计玩家数据...", "result_path": null, "start_time": "1736509800.123", "elapsed_seconds": 45.2 }

响应示例(已完成)

{ "task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "status": "completed", "mode": "pvp", "format": "xlsx", "progress": "100% - 分析完成", "result_path": "/web_results/PvP_Report_20250110_143000.xlsx", "start_time": "1736509800.123", "elapsed_seconds": 89.5, "file_size": "2.3MB" }

响应示例(失败)

{ "task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "status": "failed", "mode": "pvp", "format": "xlsx", "progress": "❌ 分析失败: 未解析到任何有效事件", "error": "日志文件不包含有效的PvP击杀记录", "result_path": null, "audit_logged": true }

💡 WebSocket替代方案(推荐)

当WebSocket可用时,建议优先使用WebSocket接收实时推送,减少服务器轮询压力。连接 /ws/progress 后自动接收JSON消息,无需手动查询。

GET

/api/download/{filename}

功能描述:安全下载分析结果文件,自动处理路径遍历防护。

路径参数

filename string 文件名(从status接口获取),如: PvP_Report_20250110_143000.xlsx

安全机制

  • 验证文件名合法性(移除非法字符,防止路径遍历)
  • 严格限制在 RESULT_DIR 目录内,禁止越权访问
  • 记录下载审计日志(download事件)
  • 仅在文件存在且可读时提供下载,返回403/404
  • 文件24小时后自动清理,请及时下载备份

响应

返回 application/octet-stream 流,HTTP头包含:

Content-Disposition: attachment; filename="PvP_Report_20250110_143000.xlsx" Content-Type: application/octet-stream Content-Length: 2457600

错误响应

404 Not Found 文件不存在或已过期
403 Forbidden 非法的文件路径访问或文件已过期
GET

/api/preview/{filename}

功能描述:在线预览图片或PDF文件(Content-Disposition: inline),支持浏览器直接渲染。

支持的文件类型

🖼️ .png 📷 .jpg/.jpeg 📄 .pdf

示例

// 新窗口打开预览 window.open('/api/preview/PvP_Report_20250110_143000.png', '_blank'); // iframe嵌入 <iframe src="/api/preview/Shop_Report_20250110_143000.pdf" width="800" height="600"></iframe>

🛡️ 安全注意

预览接口同样受路径遍历防护限制,仅允许访问 RESULT_DIR 目录下的文件。不支持预览 .xlsx.json 格式。

WS

/ws/progress

功能描述:建立WebSocket连接,接收任务进度实时推送。

连接方式

const ws = new WebSocket('ws://localhost:8000/ws/progress');

消息格式

字段 类型 说明
task_id string UUID格式,任务唯一标识
progress string 进度描述(包含百分比和阶段信息)
timestamp number 消息发送时间戳(Unix时间)

客户端示例(带自动重连)

let ws = null; let reconnectTimer = null; let currentTaskId = null; function connectWebSocket() { const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"; ws = new WebSocket(`${protocol}//${window.location.host}/ws/progress`); ws.onopen = () => { console.log('[WebSocket] 连接已建立'); ws.send(JSON.stringify({ type: 'ping' })); if (reconnectTimer) clearTimeout(reconnectTimer); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.task_id === currentTaskId) { updateProgress(data.progress); } }; ws.onclose = () => { console.log('[WebSocket] 连接关闭,5秒后重连...'); reconnectTimer = setTimeout(connectWebSocket, 5000); }; ws.onerror = (error) => { console.error('[WebSocket] 连接错误:', error); }; } // 启动分析后监听 function startAnalysis(taskId) { currentTaskId = taskId; connectWebSocket(); }

💡 最佳实践

建议优先使用WebSocket接收进度,相比轮询更及时且节省服务器资源。不可用时降级为GET /api/status轮询模式。

📦 错误处理

所有接口遵循HTTP状态码规范,错误时返回统一的JSON格式:

{ "detail": "错误描述信息", "error_id": "可选的唯一错误ID(用于追踪)", "timestamp": "2025-01-10T14:30:00+08:00" }

常见状态码详解

状态码 含义 典型场景 审计级别
200 OK 请求成功 查询状态、下载文件、预览图片 ✅ info
201 Created 资源创建成功 文件上传成功 ✅ info
400 Bad Request 请求参数错误 文件验证失败(格式不匹配/熵值超标)、无效mode/format ✅ warning
404 Not Found 资源不存在 任务ID不存在、文件已过期、下载文件已被清理 ✅ warning
403 Forbidden 访问被拒绝 IP在黑名单、非法文件路径、User-Agent被阻止 ✅ critical
413 Payload Too Large 文件大小超限 总大小>500MB或单文件>100MB ✅ warning
429 Too Many Requests 速率限制 上传/分析频率过高,灰名单计数+1 ✅ suspicious
500 Internal Server Error 服务器内部错误 分析过程异常、导出失败、文件系统错误 ✅ critical(含堆栈追踪)

🔍 调试建议

生产环境错误仅显示简要信息。查看服务器日志或审计数据库获取完整堆栈:

# 查询最近24小时的错误日志 python audit_tool.py query --action error --severity critical --hours 24 # 查看特定错误ID详情 python audit_tool.py query --action error --hours 1 | grep "error_id" # 实时监控日志 tail -f web_uploads/task_*/analysis.log # 如存在

📚 多语言代码示例

选择您的编程语言查看完整集成示例(含WebSocket自动重连):

Python
JavaScript
Java
C#
Go
Rust
PHP
cURL

Python完整示例(含WebSocket自动重连)

import asyncio import json import requests import websocket import time class MCLogAnalyzerClient: def __init__(self, base_url="http://localhost:8000"): self.base_url = base_url self.task_id = None self.ws = None self.ws_url = base_url.replace("http", "ws") def upload_files(self, file_paths: list[str]) -> str: """上传文件并启动分析""" files = [('files', open(fp, 'rb')) for fp in file_paths] # 1. 上传文件 resp = requests.post(f"{self.base_url}/api/upload", files=files) resp.raise_for_status() upload_data = resp.json() self.task_id = upload_data['task_id'] print(f"✅ 上传成功: {upload_data['file_count']} 个文件") # 2. 启动分析 analyze_resp = requests.post( f"{self.base_url}/api/analyze/{self.task_id}", data={"mode": "pvp", "output_format": "xlsx"} ) analyze_resp.raise_for_status() print(f"🚀 分析已启动,任务ID: {self.task_id}") return self.task_id def watch_progress_ws(self): """WebSocket监听进度(带自动重连)""" def on_message(ws, message): data = json.loads(message) if data.get("task_id") == self.task_id: print(f"📊 进度: {data['progress']}") if "100%" in data['progress']: ws.close() # 查询最终状态并下载 self.download_result() def on_error(ws, error): print(f"[WebSocket] 错误: {error}") def on_close(ws, close_status_code, close_msg): print(f"[WebSocket] 连接关闭({close_status_code}),5秒后重连...") time.sleep(5) self.watch_progress_ws() def on_open(ws): print("[WebSocket] 连接已建立") ws.send(json.dumps({"type": "ping"})) self.ws = websocket.WebSocketApp( f"{self.ws_url}/ws/progress", on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close ) self.ws.run_forever(ping_interval=30, ping_timeout=10) def get_status(self) -> dict: """轮询获取状态(WebSocket备选)""" resp = requests.get(f"{self.base_url}/api/status/{self.task_id}") resp.raise_for_status() return resp.json() def download_result(self): """下载结果文件""" status = self.get_status() if status['status'] == 'completed': filename = status['result_path'].split('/')[-1] resp = requests.get(f"{self.base_url}/api/download/{filename}") resp.raise_for_status() with open(filename, 'wb') as f: f.write(resp.content) print(f"📥 下载完成: {filename} ({status.get('file_size', '未知大小')})") else: print("❌ 任务尚未完成") # 使用示例 if __name__ == "__main__": client = MCLogAnalyzerClient("http://localhost:8000") client.upload_files(["pvp1.log", "pvp2.log.gz"]) client.watch_progress_ws() # WebSocket模式 # 或使用轮询模式 # while True: # status = client.get_status() # print(status['progress']) # if status['status'] in ['completed', 'failed']: # break # time.sleep(2)

⚡ 性能与最佳实践