Я помню о подобной проблеме, которая, по всей видимости, была исправлена в версии 2026.01.0-latest, поэтому я считаю, что это отдельная актуальная проблема, связанная с восстановлением после прерванной загрузки резервной копии, а не со старой ошибкой при первоначальной загрузке.
Логично предположить, что одноразовая ссылка для резервного копирования может мешать браузеру возобновлять прерванную загрузку, но загрузить резервную копию дважды по одной ссылке невозможно. Таким образом, когда загрузка прерывается один раз, возобновление, вероятно, отменяется самим Discourse.
Мне удалось воспроизвести именно это поведение в текущей версии Discourse.
Воспроизведение
Я загружал локальную резервную копию Discourse размером:
4 231 639 143 байта
с помощью Safari на iOS.
Загрузка шла нормально. У меня есть запись экрана, показывающая увеличение с примерно:
313,3 МБ до 317,8 МБ
Затем я переключился с Safari примерно на 15 секунд.
Когда я вернулся в Safari, загрузка остановилась на отметке примерно:
319,8 МБ
и 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 отклонил этот запрос Range с кодом 422.
Текущий код Discourse
Если посмотреть на текущий Admin::BackupsController#show, последовательность действий выглядит следующим образом:
EmailBackupToken.compare(current_user.id, token)
↓
find backup
↓
EmailBackupToken.del(current_user.id)
↓
send_file
Таким образом, первоначальный аутентифицированный запрос потребляет токен электронной почты до того, как передача данных в несколько гигабайт действительно завершится.
Если эта передача впоследствии прерывается, Safari отправляет другой запрос, например:
Range: bytes=319799904-
но этот запрос снова проходит через /admin/backups/…, а токен электронной почты уже был удален.
Похоже, это объясняет код 422, который я зафиксировал.
Для этого по-прежнему требуется как аутентифицированная сессия, так и токен резервной копии, поэтому я не предлагаю просто сделать существующий токен неограниченно многоразовым.
Скорее, я задаюсь вопросом, не должно ли существовать какой-то ограниченный способ, позволяющий тому же аутентифицированному администратору возобновить загрузку той же уже одобренной резервной копии.
Например, это могло бы быть кратковременное разрешение на загрузку, связанное с тем же пользователем и резервной копией, хотя у разработчиков может быть лучший способ обработки этого вопроса.
Почему это стало легче воспроизвести на iOS
Прерывание, которое выявило эту проблему, также похоже на отчеты пользователей последних версий iOS.
В сообществе Apple размещено как минимум три отчета:
более старые отчеты
«Неудачные фоновые загрузки в Safari после обновления IOS 26» — октябрь 2025 г.
Safari Background Downloads Failing After… - Apple Community
Пользователь сообщает о неудачных крупных загрузках в Safari при работе в фоновом режиме после обновления до iOS 26. Он также обновил iPhone 15 Pro до iOS 26 и сообщил о том же поведении.
«Проблема фоновой загрузки в Safari iOS — отмена при сворачивании» — декабрь 2025 г.
Safari iOS Background Download Issue - Ca… - Apple Community
Сообщено на iPhone 15 с iOS 26.1. Загрузки начинаются нормально, но отменяются после переключения на другое приложение или сворачивания Safari.
«Safari не может завершить большую загрузку» — апрель 2026 г.
Сообщено на iPhone 17 Pro Max с iOS 26.4. По сообщениям, большие загрузки приостанавливаются вскоре после блокировки устройства, переключения между Safari или перехода с сотовой сети на Wi-Fi. Автор специально указывает на хороший сигнал и говорит, что те же загрузки завершаются на ПК, Mac и Android.
Я не думаю, что этих отчетов сообщества достаточно, чтобы утверждать, что Apple подтвердила регрессию в iOS.
Однако они согласуются с моей записью экрана: резервная копия загружалась нормально, я ненадолго переключился с Safari, и когда я вернулся, передача была прервана.
Важный момент со стороны Discourse не зависит от причины прерывания:
передача большой резервной копии прервана
↓
браузер пытается возобновить загрузку с использованием стандарта Range
↓
токен резервной копии уже был использован
↓
возобновление получает код 422
Наблюдения на стороне сервера
Похоже, это не является общей проблемой с текущим путем nginx/sendfile.
Тот же путь загрузки резервной копии в несколько ГБ успешно завершался:
- из Firefox/Linux по HTTP/3; и
- с того же iPhone по Wi-Fi с использованием HTTP/3.
Текущий nginx также заявляет о поддержке диапазонов байтов.
Поэтому я не утверждаю, что HTTP/3, Caddy или nginx внутренне неспособны доставить резервную копию.
В этом конкретном случае воспроизведения исходная передача была прервана после примерно 320 МБ, Safari впоследствии отправил корректный запрос Range, и этот второй запрос был отклонен Discourse.
Имело бы смысл предусмотреть какой-либо кратковременный механизм для уже одобренной загрузки резервной копии, позволяющий тому же аутентифицированному администратору возобновить загрузку того же файла после прерванной передачи?