Мы разрабатываем сервер с REST API, который принимает и отвечает с помощью JSON. Проблема в том, если вам нужно загрузить изображения с клиента на сервер.
Примечание: а также я имею в виду случай использования, в котором сущность (пользователь) может иметь несколько файлов (carPhoto, licensePhoto), а также иметь другие свойства (имя, адрес электронной почты ...), но когда вы создаете нового пользователя, вы не Не отправляйте эти изображения, они добавляются после процесса регистрации.
Решения, о которых я знаю, но у каждого из них есть свои недостатки
1. Используйте multipart / form-data вместо JSON
хорошо : запросы POST и PUT настолько RESTful, насколько это возможно, они могут содержать текстовые вводы вместе с файлом.
минусы : это больше не JSON, его гораздо проще тестировать, отлаживать и т. д. по сравнению с multipart / form-data
2. Разрешить обновлять отдельные файлы
POST-запрос для создания нового пользователя не позволяет добавлять изображения (что нормально в нашем случае использования, как я уже говорил в начале), загрузка изображений выполняется с помощью PUT-запроса в виде multipart / form-data, например, в / users / 4 / carPhoto
хорошо : все (кроме самой загрузки файла) остается в JSON, его легко тестировать и отлаживать (вы можете регистрировать завершенные запросы JSON, не опасаясь их длины)
минусы : Это не интуитивно понятно, вы не можете POST или PUT все переменные объекта сразу, а также этот адрес /users/4/carPhoto
можно рассматривать скорее как коллекцию (стандартный сценарий использования для REST API выглядит следующим образом /users/4/shipments
). Обычно вы не можете (и не хотите) ПОЛУЧИТЬ / ПОСТАВИТЬ каждую переменную объекта, например users / 4 / name. Вы можете получить имя с помощью GET и изменить его с помощью PUT в users / 4. Если после идентификатора есть что-то, то обычно это другая коллекция, например users / 4 / reviews
3. Используйте Base64
Отправьте его в формате JSON, но закодируйте файлы с помощью Base64.
хорошо : То же, что и первое решение, это как можно RESTful сервис.
минусы : еще раз, тестирование и отладка намного хуже (тело может иметь мегабайты данных), увеличение размера, а также времени обработки как на клиенте, так и на сервере
Я действительно хотел бы использовать решение нет. 2, но у него есть свои минусы ... Кто-нибудь может дать мне лучшее представление о том, что является лучшим решением?
Моя цель состоит в том, чтобы RESTful-сервисы включали в себя как можно больше стандартов, в то время как я хочу сделать его как можно более простым.
Ответы:
OP здесь (я отвечаю на этот вопрос через два года, пост, сделанный Дэниелом Сереседо, был неплохим, но веб-сервисы развиваются очень быстро)
После трех лет постоянной разработки программного обеспечения (с акцентом на архитектуру программного обеспечения, управление проектами и архитектуру микросервисов) я определенно выбрал второй путь (но с одной общей конечной точкой) в качестве лучшего.
Если у вас есть специальная конечная точка для изображений, это дает вам гораздо больше возможностей для обработки этих изображений.
У нас один и тот же REST API (Node.js) для мобильных приложений (iOS / android) и внешнего интерфейса (с использованием React). Это 2017 год, поэтому вы не хотите хранить изображения локально, вы хотите загрузить их в какое-то облачное хранилище (Google cloud, s3, cloudinary, ...), поэтому вам нужна некоторая общая обработка их.
Наш типичный процесс заключается в том, что, как только вы выбираете изображение, оно начинает загружаться в фоновом режиме (обычно это POST on / images endpoint), возвращая вам идентификатор после загрузки. Это действительно удобно для пользователя, поскольку пользователь выбирает изображение, а затем обычно переходит к некоторым другим полям (например, адрес, имя, ...), поэтому, когда он нажимает кнопку «отправить», изображение обычно уже загружено. Он не ждет и смотрит на экран с надписью «загрузка ...».
То же самое касается получения изображений. В особенности благодаря мобильным телефонам и ограниченным объемам мобильных данных вы не хотите отправлять оригинальные изображения, вы хотите отправлять изображения с измененным размером, чтобы они не занимали слишком большую полосу пропускания (а для того, чтобы сделать ваши мобильные приложения быстрее, вам часто чтобы изменить его размер, вы хотите, чтобы изображение идеально вписывалось в ваш взгляд). По этой причине хорошие приложения используют что-то вроде облачного хранилища (или у нас есть собственный сервер изображений для изменения размера).
Кроме того, если данные не являются частными, то вы отправляете обратно в app / frontend только URL-адрес и загружаете его напрямую из облачного хранилища, что значительно экономит трафик и время обработки вашего сервера. В наших больших приложениях загружается много терабайт каждый месяц, и вы не хотите обрабатывать это непосредственно на каждом из ваших REST API-серверов, которые сосредоточены на работе CRUD. Вы хотите обработать это в одном месте (наш Imageserver, который имеет кэширование и т. Д.) Или позволить облачным службам обрабатывать все это.
Минусы: Единственные «минусы», о которых вы должны подумать, это «не назначенные изображения». Пользователь выбирает изображения и продолжает заполнять другие поля, но затем он говорит «нет» и выключает приложение или вкладку, но между тем вы успешно загрузили изображение. Это означает, что вы загрузили изображение, которое нигде не назначено.
Есть несколько способов справиться с этим. Самый простой вариант - «Мне все равно», который уместен, если это происходит не очень часто или у вас даже есть желание сохранить каждое изображение, отправленное вами пользователем (по любой причине), и вы не хотите ничего удаление.
Другой вариант тоже прост - у вас есть CRON, то есть каждую неделю, и вы удаляете все неназначенные изображения старше одной недели.
источник
Есть несколько решений :
Первое о пути к ресурсу :
Смоделируйте изображение как ресурс самостоятельно:
Вложено в пользователя (/ user /: id / image): отношения между пользователем и изображением устанавливаются неявно
В корневом пути (/ изображение):
Клиент несет ответственность за установление отношений между изображением и пользователем, или;
Если контекст безопасности предоставляется с запросом POST, используемым для создания изображения, сервер может неявно установить связь между аутентифицированным пользователем и изображением.
Вставить изображение как часть пользователя
Второе решение о том, как представить ресурс изображения :
Это будет мой трек решения:
Тогда возникает вопрос: влияет ли производительность на выбор base64 против multipart? , Мы могли бы подумать, что обмен данными в многочастном формате должен быть более эффективным. Но эта статья показывает, насколько мало оба представления отличаются по размеру.
Мой выбор Base64:
источник
Ваше второе решение, пожалуй, самое правильное. Вы должны использовать спецификации HTTP и mimetypes так, как они были предназначены, и загружать файл через
multipart/form-data
. Что касается обработки отношений, я бы использовал этот процесс (помните, что я ничего не знаю о ваших предположениях или дизайне системы):POST
чтобы/users
создать пользовательский объект.POST
изображение/images
, чтобы убедиться, что вы возвращаетеLocation
заголовок, где изображение может быть получено в соответствии со спецификацией HTTP.PATCH
чтобы/users/carPhoto
и присвоить ему идентификатор фотографии , приведенной вLocation
заголовке шага 2.источник
Там нет простого решения. У каждого способа есть свои плюсы и минусы. Но канонический способ использовать первый вариант:
multipart/form-data
. Как говорится в руководстве по рекомендациям W3На самом деле мы не отправляем формы, но все еще применяется неявный принцип. Использование base64 в качестве двоичного представления некорректно, потому что вы используете неправильный инструмент для достижения своей цели, с другой стороны, второй вариант заставляет ваших клиентов API выполнять больше работы, чтобы использовать вашу службу API. Вы должны выполнить тяжелую работу на стороне сервера, чтобы предоставить простой в использовании API. Первый вариант нелегко отладить, но когда вы это делаете, он, вероятно, никогда не изменится.
Использование
multipart/form-data
Ты наклеить с REST / HTTP философии. Вы можете посмотреть ответ на подобный вопрос здесь .Другой вариант, если смешивать альтернативы, вы можете использовать multipart / form-data, но вместо того, чтобы отправлять каждое значение отдельно, вы можете отправить значение с именем payload с полезной нагрузкой json внутри. (Я попробовал этот подход с использованием ASP.NET WebAPI 2 и работает нормально).
источник