崩溃报告上传(mclo.gs)
基本信息
| 属性 | 值 |
|---|---|
| 端点 | https://api.mclo.gs/1/log |
| 方法 | POST |
| Content-Type | application/x-www-form-urlencoded |
| Accept | application/json |
| 唯一实现 | MclogsUploadService(注册名 mclo.gs) |
| 可配置服务数 | 1(CrashReportUpload 的 services map 只 put 了一条) |
调用链
GuiProblemScreen.actionPerformed (id=2)
└─ 新建线程 "BetterCrashes report uploading"
└─ CrashReportUpload.uploadCrashReport(report.getCompleteReport())
└─ services.get(config.crashLogPasteService)
└─ MclogsUploadService.upload(contents)
└─ 返回 URL → 写入 volatile pasteLink + 复制到剪贴板
HTTP 细节(读自 HttpUtils.createConnection)
| 项 | 值 |
|---|---|
| 连接超时 | 50000 ms(50 s) |
| 读取超时 | 20000 ms(20 s) |
| 跟随重定向 | true |
| 使用缓存 | false |
| User-Agent | BetterCrashes/<VERSION> |
请求体:content= + URLEncoder.encode(报告全文, UTF-8)。
响应解析
用 Gson 解析为 JsonObject,判定 success 字段:
success == true→ 取url字段构造java.net.URL返回- 其它情况 → 返回
null(不抛异常)
调用方 GuiProblemScreen(:130-146)据此把按钮文案切成
openUploadedCrashReport(绿字,链接已进剪贴板)或 failed。
⚠️ 只有 IOException 被 catch(:141);Gson 解析非 JSON 响应会抛
JsonSyntaxException(RuntimeException,不被捕获)⇒ 线程死掉、
按钮永久停留在 “Uploading…”。
服务回退
crashLogPasteService 配了未知服务名时,
CrashReportUpload.uploadCrashReport(:22-27)会
logger.warn 后回退到 mclo.gs(唯一可选项),
不会直接失败。
源码核对(2026-10-01 审计)
- ⚠️ 连接超时(50s) > 读取超时(20s) 是反直觉的(
HttpUtils.java:12-13)。 正常语义应是连接快、读取慢。源码就是这样写的,未做修正, 写条目时不要「顺手改成」20s/50s 以外的值。 - ⚠️ 源码缺陷:没有
getErrorStream()处理。MclogsUploadService.java:42直接读connection.getInputStream(), 服务端返回 4xx/5xx 时该调用抛IOException。 好在调用方 catch 了IOException并显示failed,行为可接受, 但拿不到服务端返回的错误正文。 - ⚠️ 源码缺陷:按钮最长可卡 70 秒。上传在主线程之外的裸
new Thread(...)中执行(GuiProblemScreen.java:125, 150), 期间按钮被enabled = false(:122)。连接 50 s + 读取 20 s ⇒ 极端情况下玩家要等 70 s。 - ⚠️ UI 线程安全不一致:
pasteLink是volatile(:47), 写入时也用synchronized (button)保护按钮状态, 但button.displayString的读在actionPerformed(主线程)、 写在上传线程 —— 同步块只包住写侧。 - 上传的是
report.getCompleteReport()(完整报告全文), 不是落盘的 txt 文件 ⇒ 即使日志被限流未落盘,照样可以上传。 - README 声明的上传目标是 mclo.gs:https://mclo.gs/