之前曾出现过备份下载问题,该问题似乎在 2026.01.0-latest 版本中已得到修复。我认为这是一个独立的当前问题,涉及从中断的备份下载中恢复,而非旧的初始下载失败。
在之前的讨论中,有人提出一种可能性:一次性备份链接可能会阻止浏览器恢复中断的下载:一旦第一个请求消耗了该链接,后续的恢复请求可能不再被授权。
我目前已在当前的 Discourse 上成功复现了这种行为。
复现步骤
我正在下载一个本地 Discourse 备份,大小为:
4,231,639,143 字节
使用的是 iOS 上的 Safari 浏览器。
下载正在正常进行。我有一段屏幕录像,显示其从大约:
313.3 MB 增加到 317.8 MB
然后我离开 Safari 仅约 15 秒。
当我返回 Safari 时,下载已停止在大约:
319.8 MB
并且 Safari 显示了其重试控件。
原始请求的 Caddy 访问日志显示:
GET /admin/backups/...
HTTP/3
Range: none
status: 200
Content-Length: 4231639143
size: 319864024
然后我使用了 Safari 自带的重试控件。
Safari 发出了一个真正的 HTTP 字节范围请求:
GET /admin/backups/...
HTTP/3
Range: bytes=319799904-
status: 422
因此,Safari 并不是简单地尝试进行另一次完整下载。它正确地试图从上次传输停止的大约位置恢复现有文件。
Discourse 以 422 状态码拒绝了该 Range 请求。
当前 Discourse 代码
查看当前的 Admin::BackupsController#show,其流程实际上为:
EmailBackupToken.compare(current_user.id, token)
↓
find backup
↓
EmailBackupToken.del(current_user.id)
↓
send_file
因此,初始的经过身份验证的请求会在多 GB 传输实际完成之前消耗电子邮件令牌。
如果该传输随后被中断,Safari 会发出另一个请求,例如:
Range: bytes=319799904-
但该请求再次通过 /admin/backups/… 处理,而电子邮件令牌已经被删除。
这似乎解释了我捕获到的 422 错误。
除了备份令牌外,仍然需要经过身份验证的会话,因此我并不是建议简单地让现有令牌无限期可重用。
相反,我在思考是否应该有一种有限制的方式,让同一位经过身份验证的管理员能够恢复同一个已授权备份的下载。
例如,这可能是一个与同一用户和备份相关联的短时效下载授权,尽管维护者可能有更好的处理此问题的方法。
为什么这在 iOS 上变得更容易复现
暴露此问题的中断似乎与来自最近 iOS 版本用户的报告类似。
Apple Community 上至少有三个相关报告:
较早的报告
“Safari 在 iOS 26 更新后后台下载失败” — 2025 年 10 月
Safari Background Downloads Failing After… - Apple Community
该用户报告称,升级到 iOS 26 后,Safari 在后台运行时较大的下载会失败。他们还将 iPhone 15 Pro 升级到 iOS 26,并报告了相同的行为。
“Safari iOS 后台下载问题 - 最小化时取消” — 2025 年 12 月
Safari iOS Background Download Issue - Ca… - Apple Community
在运行 iOS 26.1 的 iPhone 15 上报告。下载开始时正常,但在切换到另一个应用或最小化 Safari 后取消。
“Safari 无法完成大型下载” — 2026 年 4 月
在运行 iOS 26.4 的 iPhone 17 Pro Max 上报告。据报告,大型下载在锁定设备后不久暂停,或者在蜂窝数据和 Wi-Fi 之间切换时暂停。作者特别报告信号良好,并表示相同的下载在 PC、Mac 和 Android 上可以完成。
我认为这些社区报告不足以说明 Apple 已确认 iOS 存在回归问题。
然而,它们与我的屏幕录像是一致的:备份正在正常下载,我短暂离开了 Safari,当我返回时传输已中断。
Discourse 端的重要观点与中断发生的原因无关:
大型备份传输被中断
↓
浏览器尝试基于标准的 Range 恢复
↓
备份令牌已被消耗
↓
恢复请求收到 422
服务器端观察
这似乎不是当前 nginx/sendfile 路径的一般性问题。
相同的几 GB 备份路径已成功完成:
- 通过 HTTP/3 从 Firefox/Linux;以及
- 通过 Wi-Fi 使用 HTTP/3 从同一部 iPhone。
当前的 nginx 也宣传支持字节范围。
因此,我并不是建议 HTTP/3、Caddy 或 nginx 本质上无法提供备份。
在这次特定的复现中,原始传输在大约 320 MB 后中断,Safari 随后发出了一个看似有效的 Range 请求,而该第二个请求被 Discourse 拒绝。
对于已经授权的备份下载,是否应该有一种短时效机制,允许同一位经过身份验证的管理员在中断传输后恢复该同一文件的下载?