Как должен выглядеть API для загрузки больших файлов с возможностью возобновления
Что проверяют
Умеете ли вы спроектировать протокол, который переживает обрыв связи, а не просто принять файл контроллером. Главное: как клиент узнаёт, с какого места продолжить, и что будет при повторной отправке того же куска. Следом часто спрашивают, почему бы не грузить прямо в объектное хранилище.
Как отвечать
Опишите загрузку как сессию:
- создание:
POST /uploadsс именем, размером и хешем. Сервер проверяет права и лимиты и возвращает201с адресом сессии вLocation; - куски:
PUTилиPATCH /uploads/{id}сContent-Rangeили смещением, сервер пишет байты по этому смещению и отвечает, сколько принято; - прогресс:
HEAD /uploads/{id}отдаёт текущее смещение, с него клиент продолжает после обрыва; - завершение:
POST /uploads/{id}/complete, сервер сверяет размер и хеш и переносит файл в постоянное хранилище; - очистка: брошенные сессии удаляет фоновая задача на
IHostedServiceпо TTL.
Хорошо сослаться на готовые протоколы: tus (заголовок Upload-Offset, для .NET есть tusdotnet) и S3 multipart upload, где до 10 000 частей и каждая, кроме последней, не меньше 5 МБ. Часто лучший ответ такой: API выдаёт presigned URL на части, байты идут прямо в хранилище, а сервис ведёт только метаданные.
Для ASP.NET Core: у Kestrel MaxRequestBodySize по умолчанию около 30 МБ, меняется через [RequestSizeLimit]. Тело читают потоком из Request.Body, а не через IFormFile, который буферизует файл на диск.
Где спотыкаются
Пишут кусок через FileMode.Append. Повтор после таймаута дописывает те же байты второй раз. Запись должна идти по смещению, а расхождение со смещением сервера давать 409.
Держат состояние сессии в памяти процесса. После перезапуска или на втором экземпляре за балансировщиком загрузка не продолжится.
Не проверяют целостность. Без хеша куска и всего файла о битых данных вы узнаете от пользователя.