Лучший подход к созданию веб-службы отдыха с бинарными данными, которые будут потребляться из браузера
Я разрабатываю веб-сервис 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 кодировать файл на клиенте
некоторые полезные ресурсы:
Ответы
Ответ 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.