崩溃报告上传(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/