Подтвердить что ты не робот

Лучший подход к созданию веб-службы отдыха с бинарными данными, которые будут потребляться из браузера

Я разрабатываю веб-сервис json rest, который будет использоваться из одного приложения веб-страницы, созданного с помощью backbone.js

Этот API позволит пользователю загружать файлы, связанные с каким-либо объектом, например, в виде PDF-отчетов, связанных с проектом

Перейдя по ссылкам и выполняя некоторые исследования при переполнении стека, я пришел с этими возможными подходами:

Первый подход: поле данных с кодировкой base64

POST: /api/projects/234/reports
{
  author: 'xxxx',
  abstract: 'xxxx',
  filename: 'xxxx',
  filesize: 222,
  content: '<base64 encoded binary data>'
}

Второй подход: многостраничное сообщение:

POST: /api/projects/234/reports
{
  author: 'xxxx',
  abstract: 'xxxx',
}

в качестве ответа я получу идентификатор отчета, и с этим я выведу другой пост

POST: /api/projects/234/reports/1/content
enctype=multipart/form-data

а затем просто отправьте двоичные данные

(посмотрите на это: qaru.site/info/15447/...)

Третий подход: отправьте двоичные данные на отдельный ресурс и сохраните href

сначала я генерирую случайный ключ на клиенте и размещаю там двоичный контент

POST: /api/files/E4304205-29B7-48EE-A359-74250E19EFC4
enctype=multipart/form-data

а затем

POST: /api/projects/234/reports
{
  author: 'xxxx',
  abstract: 'xxxx',
  filename: 'xxxx',
  filesize: 222,
  href: '/api/files/E4304205-29B7-48EE-A359-74250E19EFC4'
}

(см. это: qaru.site/info/209173/...)

Я просто хотел узнать, есть ли какой-либо другой подход, который я мог бы использовать, плюсы/минусы каждого, и если есть какой-либо установленный способ справиться с такими требованиями

большой con, который я вижу в первом подходе, заключается в том, что мне приходится полностью загружать и base64 кодировать файл на клиенте

некоторые полезные ресурсы:

4b9b3361

Ответ 1

Результаты моих исследований:

  • Одиночный запрос (данные включены)

    Запрос содержит метаданные. Данные являются свойством метаданных и закодированы (например: Base64).

    Плюсы:

    • транзакционной
    • каждый раз действительный (отсутствуют отсутствующие метаданные или данные)

    Минусы:

    • кодирование делает запрос очень большим

    Примеры:

  • Одиночный запрос (multipart)

    Запрос содержит одну или несколько частей с метаданными и данными.

    Типы контента:

    Плюсы:

    • транзакционной
    • каждый раз действительный (отсутствуют отсутствующие метаданные или данные)

    Минусы:

    • Согласование типов содержимого является сложным.
    • тип содержимого для данных не отображается в WADL

    Примеры:

    • Confluence (с частями для данных и метаданных)
    • Jira (с одной частью для данных, метаданных только заголовки деталей для имени файла и типа mime)
    • Bitbucket (с одной частью для данных, без метаданных)
    • Google Диск (с одной частью для метаданных и один для данных детали)
  • Одиночный запрос (метаданные в заголовке и URL-адресе HTTP)

    Тело запроса содержит данные и заголовок HTTP, а URL содержит метаданные.

    Плюсы:

    • транзакционной
    • каждый раз действительный (отсутствуют отсутствующие метаданные или данные)

    Минусы:

    • нет возможных вложенных метаданных
  • Два запроса

    Один запрос для метаданных и один или несколько запросов для данных.

    Плюсы:

    • масштабируемость (например: запрос данных может поступать на сервер репозитория)
    • возобновить (см., например, Google Диск)

    Минусы:

    • не транзакционный
    • не каждый раз действительный (перед вторым запросом, одна часть отсутствует)

    Примеры:

Ответ 2

Я не могу думать о каких-либо других подходах с моей головы.

Из ваших 3 подходов я больше всего работал с методом 3. Самая большая разница, которую я вижу, заключается в первом методе и втором: Разделение метаданных и содержимого на 2 ресурса

  • Pro: Масштабируемость
    • в то время как ваше решение включает отправку на тот же сервер, это можно легко изменить, чтобы указать загрузку контента на отдельный сервер (то есть Amazon S3)
    • В первом методе тот же сервер, который обслуживает метаданные для пользователей, будет заблокирован процессом с большой загрузкой.
  • Con: потерянные данные/добавленная сложность
    • неудачные загрузки (либо метаданные, либо содержимое) оставят потерянные данные на сервере DB
    • Сиротские данные могут быть очищены с запланированным заданием, но это добавляет сложность кода.
    • Метод II уменьшает возможности для сирот за счет более длительного ожидания клиента, поскольку вы блокируете ответ первого POST

Первый метод кажется наиболее простым для кода. Тем не менее, я бы пошел только с первым методом, если вы ожидаете, что эта служба используется редко, и вы можете установить разумный предел для загрузки файлов пользователя.

Ответ 3

Я считаю, что конечный метод - это номер 3 (отдельный ресурс) по основной причине, что он позволяет максимизировать значение, которое я получаю из стандарта HTTP, который соответствует тому, как я думаю о REST API. Например, при использовании обоснованного HTTP-клиента вы получаете следующие преимущества:

  • Контент сжатия. Вы оптимизируете, позволяя серверам отвечать сжатым результатом, если клиенты указывают, что они поддерживают, ваш API не изменился, существующие клиенты продолжают работать, будущие клиенты могут его использовать.
  • Кэширование: If-Modified-Since, ETag и т.д. Клиенты могут запретить повторный набор двоичных данных
  • Абстракция типа контента: например, вам требуется загруженное изображение, оно может быть типов image/jpeg или image/png. Заголовки HTTP Принять и Content-type предоставляют нам элегантную семантику для согласования этого между клиентами и серверами без необходимости жестко кодировать все это как часть нашей схемы и/или API

С другой стороны, я считаю справедливым заключить, что этот метод не является самым простым, если данные двоичных данных не являются необязательными. В этом случае в игру войдут минусы, перечисленные в Eric Hu.