Стандартный метод частичной загрузки HTTP, возобновление загрузки

Я разрабатываю инфраструктуру http client/server и ищу правильный способ обработки частичных загрузок (так же, как и при загрузке с использованием метода GET с заголовком Range).

Но HTTP PUT не предназначен для возобновления. И метод PATCH, как я знаю, не принимает заголовок Range.

Есть ли способ обработать это по стандарту HTTP (не используя заголовки расширений или т.д.)?

Спасибо заранее.

Ответ 1

Я думаю, что нет стандартного для частичной загрузки:

  • Внутренний запрос Content-Range внутри явно запрещен в RFC2616 (http), но также формулировка относится к нему как к заголовку ответа который используется в ответ на запрос диапазона
  • в то время как вы можете использовать метод PATCH для обновления существующего ресурса (например, для добавления большего количества байтов), это будет не то же самое, что частичная загрузка, потому что все время доступный неполный ресурс будет

Если вы посмотрите на протоколы Dropbox, google drive и т.д., все они сворачивают свой собственный протокол для передачи отдельных файлов в несколько фрагментов. Что нужно для возобновляемых загрузок -

  • способ устранения неполной загрузки. Обычные URL-адреса адресуют полный, а не частичный ресурс, и я не знаю стандартного для частичных ресурсов.
  • чтобы узнать текущее состояние загрузки, возможно, также контрольные суммы части, чтобы убедиться, что локальный файл не изменился. Это может быть обеспечено с помощью метода WebDAV PROPFIND (как только вы сможете обратиться к неполному ресурсу:)
  • способ загрузки фрагмента. Здесь можно было бы использовать PATCH с заголовком диапазона содержимого. mod_dav позволяет PUT с заголовком диапазона содержимого (см. http://www.gossamer-threads.com/lists/apache/users/432346)
  • способ публикации ресурса после его завершения или способ определения заранее, какие полные средства (например, размер ресурса, контрольная сумма...)

Ответ 2

Как отмечалось в некоторых комментариях, более новые версии спецификации HTTP прояснили это несколько. Per Раздел 4.3.4 RFC 7231:

Исходный сервер, который позволяет PUT на заданном целевом ресурсе ДОЛЖЕН отправлять ответ 400 (неверный запрос) на запрос PUT, который содержит Поле заголовка Content-Range (Раздел 4.2 [RFC7233]), поскольку полезная нагрузка скорее всего, будет частичным контентом, который был ошибочно PUT как полный представление. Обновления частичного контента возможны путем таргетинга на отдельно идентифицированный ресурс с состоянием, которое перекрывает часть больший ресурс или с помощью другого метода, который был специально для частичных обновлений (например, метод PATCH, определенный в [RFC5789]).

К сожалению, обсуждение заголовков диапазонов, которое встречается в RFC 7233, более или менее полностью фокусируется на запросах GET, а RFC 5789 определяет почти ничего о PATCH, за исключением того, что специально не требуется передавать весь контент (но разрешено), и не требуется быть идемпотентным (но разрешено быть).

Яркая сторона состоит в том, что, поскольку PATCH настолько слабо определен, он учитывает подход, заданный в ответе на связанный с ним вопрос (fooobar.com/questions/92092/...): просто измените "PUT" - "PATCH". В то время как нет требования, чтобы сервер интерпретировал запрос PATCH с заголовком Content-Range таким образом, это, безусловно, допустимая интерпретация, а не одна, на которую можно положиться с произвольных серверов или клиентов. Но в таких случаях, как исходный вопрос, где имеется доступ к обоим концам, это, по крайней мере, очевидный подход и не нарушает существующих стандартов.

Еще одно соображение заключается в том, что Content-Type должен выражать то, что передается, а не тип контента объекта в целом (RFC дает несколько примеров в этом отношении). Для контента, который "исправляется" в произвольных фрагментах, это подразумевает использование приложения/октета-потока, хотя существуют сценарии, в которых клиент и сервер могут быть более осведомлены о контенте и могут отправлять патчи как объекты, которые имеют более конкретное определение (например, отдельные страницы формата многостраничного изображения).

Ответ 3

Используйте заголовок Range xxxx- yyyy или заголовок Range xxxx- с PUT для обновления части файла. Поддерживается Apache.

Не смущайтесь утверждением в RFC 7231, что Content-Range нельзя использовать. Это сделано для того, чтобы клиенты не брали заголовки, полученные с сервера, и использовали PUT для отправки их обратно на сервер. Это предупреждение не относится к вопросу частичных ставок.

Ответ 4

PATCH был бы логичным методом для возобновляемых загрузок: он ожидает тип мультимедиа, который указывает, как изменить целевой ресурс. Хотя он не определен как формат для выполнения исправления, multipart/byteranges определяет диапазон байтов и содержимое этого диапазона, что делает его подходящим образом определенным для полезных нагрузок PATCH.

Пример:

PATCH /document HTTP/1.1
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES

--THIS_STRING_SEPARATES
Content-Type: text/plain
Content-Range: bytes 10-21/22

1234567890
--THIS_STRING_SEPARATES--

Этот пример загружает двенадцать байтов со смещением в десять байтов. THIS_STRING_SEPARATES - произвольный выбранный пользователем разделитель, который должен генерироваться случайным образом. Некоторые заголовки опущены для краткости, каждая строка заканчивается на with.