Это первая часть из серии постов о Храм .
Цель этой серии статей — показать преимущества Shrine перед существующими загрузчиками файлов.
Прошло больше года с тех пор, как я начал разработку Shrine. За это время Shrine получил много интересного функционала, экосистема значительно разрослась и достаточное количество разработчиков стало использовать Shrine в производстве.
Прежде чем мы углубимся в объяснение преимуществ, нам нужно сделать шаг назад и подробно рассмотреть, что в первую очередь мотивировало разработку Shrine. В частности, я хочу поговорить об ограничениях существующих загрузчиков.
Я думаю, что важно знать об этих ограничениях, чтобы вы могли сделать выбор, который лучше всего подходит. требования .
Требования Требования были следующие:
Файлы на Amazon S3 необходимо загружать напрямую.Обработка и удаление файлов должны выполняться в фоновом режиме.
Обработка может выполняться во время процесса загрузки.
Интеграция с Продолжение Возможность использования с фреймворками, отличными от Rails. На мой взгляд, первые два пункта очень важны, поскольку позволяют добиться оптимальной производительности пользовательского интерфейса при работе с формами.
Но последние два пункта также не следует игнорировать: 1. Использование Amazon S3 или аналогов позволяет оптимизировать процесс скачивания файлов.
Это определенно имеет ряд преимуществ: снижение потребления ресурсов, горизонтальное масштабирование с инкапсуляцией хранилища, работа с облачными решениями типа Heroku, которые не предоставляют возможности записи дисков и иметь ограничение на время выполнения запроса .
2. Обработка и удаление файлов в фоновых задачах дает возможность работать с файлами.
асинхронно Независимо от того, храните ли вы файлы в локальной файловой системе или во внешнем хранилище, таком как Amazon S3, это значительно улучшит взаимодействие с пользователем.
Использование фоновых задач также необходимо для поддержания высокой пропускной способности вашего приложения, поскольку рабочие процессы не будут привязаны к медленным запросам.
3. Обработка при загрузке отлично работает с небольшими файлами, особенно когда создается несколько версий файлов, например изображения разных размеров.
с другой стороны, обработка загрузки также необходима для больших файлов, таких как видео.
Поэтому нам нужна библиотека, которая сможет работать с файлами любого типа.
4. Использование с ORM, отличным от ActiveRecord, также очень важно.
Поскольку уже появились более функциональные и производительные ORM для Ruby. 5. Наконец-то в Ruby-сообществе появились достойные альтернативы Rails. Нам нужна возможность легко интегрироваться с любым веб-фреймворком.
Теперь пройдемся по существующим библиотекам и рассмотрим их основные недостатки с учетом требований.
Скрепка для бумаг
Простое управление вложениями файлов для ActiveRecordС Paperclip можно попрощаться, поскольку существует сильная зависимость от ActiveRecord. Поскольку это очень распространенная библиотека, которая используется с ActiveRecord, давайте все же пройдемся по остальным требованиям.
Прямая загрузка
Paperclip не имеет возможности прямой загрузки.Может быть использован aws-sdk сгенерировать ссылку и параметры для прямой загрузки в S3 и затем отредактировать атрибуты модели так же, как при загрузке файла через Paperclip. Однако Paperclip работает только с одним репозиторием.
Для работы необходимо, чтобы все загрузки происходили непосредственно в основное хранилище S3. Это приводит к проблеме безопасности, поскольку злоумышленник может загружать файлы, не прикрепляя их, что может привести к созданию множества потерянных файлов.
Было бы намного проще, если бы S3 сделал это за тебя .
Фоновые задачи
Используется для фоновых задач.Однако Delayed_paperclip запускает задачи только после полной загрузки файла.
Это означает, что если вы не хотите или не можете выполнять прямую загрузку в S3, вашим пользователям придется загрузить файл дважды (сначала в приложение, затем в хранилище), прежде чем произойдет какая-либо фоновая обработка.
И это очень медленно.
Кроме того, Delayed_paperclip не поддерживает удаление файлов в фоновом режиме.
Это большой недостаток, поскольку вам придется делать HTTP-запрос для каждой версии файла (если у вас есть несколько версий файлов, хранящихся на S3).
Не ждите, что эта функция будет добавлена, потому что Скрепка также проверяет наличие каждой версии перед удалением.
.
Конечно, вы можете отключить удаление файлов, но тогда у вас возникнет проблема с потерянными файлами.
Окончательно, Delayed_paperclip теперь привязан к ActiveJob. , а это значит, что вы больше не сможете напрямую использовать его с библиотеками для фоновых задач.
Ложноположительное обнаружение спуфинга-атаки мим-типа
Paperclip имеет функцию обнаружения попыток подделать MIME-тип файла.Однако эта функциональность часто работает ошибочно, что приводит к возможности возникновения ошибки проверки, даже если расширение файла соответствует содержимому файла.
Это достаточно решающий фактор, поскольку в этом случае ложное срабатывание может сильно раздражать пользователей.
Конечно, вы можете отключить эту функциональность, но это сделает приложение уязвимым для атаки при загрузке файлов .
ПеревозчикВолна
Отличное решение для загрузки файлов для Rails, Sinatra и других веб-фреймворков.ПеревозчикВолна ответ Paperclip, который сохранил конфигурацию прямо в модели, инкапсуляцию в классы.
CarrierWave доступен Интеграция сиквела .
К сожалению для расширений перевозчикwave_backgrounder И несущаяwave_direct Интеграции CarrierWave ORM недостаточно.
Чтобы все это работало, требуется много дополнительного кода, специфичного для ActiveRecord.
Прямая загрузка
Как упоминалось ранее, в экосистеме CarrierWave есть решения для прямой загрузки в S3 — несущаяwave_direct .Принцип работы заключается в том, что он позволяет вам создать форму для загрузки непосредственно в S3, а затем назначить ключ S3 загруженного файла вашему загрузчику.
Однако что, если вам нужно выполнить несколько загрузок непосредственно на S3? В README отмечается, что Carerwave_direct предназначен только для одиночных загрузок.<!-- Form submits to " https://my-bucket.s3-eu-west-1.amazonaws.com " --> <%= direct_upload_form_for @photo.image do |f| %> <%= f.file_field :image %> <%= f.submit %> <% end %>
А как насчет JSON API? Это обычная форма, все, что она делает, это генерирует URL-адрес и параметры для загрузки в S3, так почему же Carrierwave_direct не позволяет вам получить эту информацию в формате JSON?
Что, если вместо повторной реализации всей логики генерации запросов на S3, используя туман-оу просто полагался на aws-sdk ? # aws-sdk
bucket = s3.bucket("my-bucket")
object = bucket.object(SecureRandom.hex)
presign = object.presigned_post
<!-- HTML version -->
<form action="<%= presign.url %>" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<% presign.fields.each do |name, value| %>
<input type="hidden" name="<%= name %>" value="<%= value %>">
<% end %>
<input type="submit" value="Upload">
</form>
# JSON version
{ "url": presign.url, "fields": presign.fields }
Этот метод имеет следующие преимущества: он не привязан к Rails, работает с JSON API, поддерживает множественную загрузку файлов (клиент может просто сделать запрос с этими данными для каждого файла), он более надежен (поскольку параметры теперь генерируются официально поддерживаемым драгоценным камнем).
Фоновые задачи
Во-первых, стоит отметить, что Carrierwave_direct предоставляет инструкции по настройке фоновой обработки.Однако правильная настройка фоновых задач это довольно сложная задача , поэтому имеет смысл положиться на библиотеку, которая сделает это за вас.
Что подводит нас к перевозчикwave_backgrounder .
Эта библиотека поддерживает обработку фоновых задач, но, по моему опыту, она работала нестабильно ( 1 , И 2 ).
Кроме того, он не поддерживает фоновое удаление файлов, что является решающим фактором при удалении большого количества файлов.
Даже если мы всё это преодолеем, интегрировать Carrierwave_backgrounder с Carerwave_direct не получится.
Как я уже упоминал, я хочу загружать файлы непосредственно в S3, а также обрабатывать и удалять их в фоновых задачах.
Но похоже, что эти две библиотеки несовместимы друг с другом, а это значит, что я не могу добиться желаемой производительности с CarrierWave для своих случаев.
Закрытие нерешенных проблем на Github
Я понимаю, что иногда люди бывают неблагодарны к мейнтейнерам популярных open-source библиотек и стоит быть мягче и уважительнее друг к другу.Тем не менее , я Я не могу понимать , Почему Разработчики ПеревозчикВолна закрываются нерешенный задания .
Один Одной из таких закрытых задач является ненужное выполнение обработки CarrierWave перед проверкой.
Это серьезная дыра в безопасности, поскольку злоумышленник может передать процессору изображений любой файл, поскольку проверки размера файла/MIME/измерений будут выполняться только после обработки.
Это делает ваше приложение уязвимым для таких атак, как ИзображениеTragick , имиджевые бомбы или просто загрузите большие изображения.
Перезалить
Загрузка файлов в Ruby, попытка №3Перезалить был создан Йонасом Никласом, автором CarrierWave, как третья попытка улучшить загрузку файлов в Ruby Как и Dragonfly, Refile был разработан для обработки на лету.
После борьбы со сложностью CarrierWave я нашел простой и современный дизайн Refile действительно многообещающим, поэтому начал вносить в него свой вклад, и в конце концов меня пригласили присоединиться к основной команде.
Refile.attachment_url(@photo, :image, :fit, 400, 500) # resize to 400x500
#=> "/attachments/15058dc712/store/fit/400/500/ed3153b9cb"
Некоторые из новых идей Refile включают: временное и постоянное хранилище в качестве хранилищ первого порядка, чистые абстракции для хранения, абстракцию ввода-вывода, чистый внутренний дизайн (без объектов GOD) и прямую загрузку из коробки.
Благодаря чистому дизайну Refile создать интеграцию с Sequel было довольно просто.
Прямая загрузка
Refile — это первая библиотека загрузки файлов со встроенной поддержкой прямых загрузок, позволяющая асинхронно загружать прикрепленный файл в тот момент, когда пользователь его выбирает. Вы можете загрузить файл через Rack или напрямую в S3, используя Refile для генерации параметров запроса S3. Существует даже библиотека JavaScript, которая сделает все за вас.
<%= form.attachment_field :image, presigned: true %>
Здесь также наблюдается значительный прирост производительности.
Когда вы загружаете файл непосредственно на S3, вы загружаете его в каталог корзины, помеченный как «временный».
Затем, когда проверка пройдет и запись будет сохранена, загруженный файл перемещается в постоянное хранилище.
Если временное и постоянное хранилище находится на S3, то вместо повторной загрузки Refile просто выдаст запрос S3 COPY. Слов нет, мои требования по прямой загрузке были выполнены.
Фоновые задачи
Одним из ограничений Refile является отсутствие поддержки фоновых заданий.Вы можете подумать, что, поскольку Refile выполняет обработку при загрузке и имеет оптимизацию S3 COPY, фоновые задачи не нужны.
Однако запрос S3 COPY по-прежнему является HTTP-запросом и влияет на время отправки формы.
Кроме того, скорость запроса S3 COPY зависит от размера файла, поэтому чем больше файл, тем медленнее будет запрос S3 COPY. Кроме того, Amazon S3 — это лишь один из многих сервисов облачного хранения; вы можете использовать другой сервис, который лучше соответствует вашим потребностям, но не имеет такой же оптимизации и даже не поддерживает прямую загрузку.
Обработка во время загрузки
Я считаю, что обработка при загрузке отлично подходит для изображений, которые хранятся локально и быстро обрабатываются.Однако если вы храните оригиналы на S3, то Refile будет обслуживать запрос исходной версии гораздо медленнее, поскольку сначала необходимо загрузить оригинал с S3. В этом случае нужно подумать о добавлении фоновых задач, предварительно обрабатывающих все версии.
Если вы загружаете файлы большего размера, например видео, обычно лучше обрабатывать их после загрузки, а не во время загрузки.
Но Refile в настоящее время не поддерживает это.
Стрекоза
Ruby gem для обработки во время загрузки — подходит для загрузки изображений в Rails, SinatraСтрекоза Это еще одно решение для обработки при загрузке, которое существует гораздо дольше, чем Refile, и, на мой взгляд, имеет гораздо более продвинутые и гибкие возможности обработки при загрузке.
Dragonfly не работает с Sequel, этого и следовало ожидать, я бы даже адаптер написал, но общее поведение, связанное с моделью кажется, смешано с поведением, специально для моделей ActiveRecord , поэтому не понятно, как это сделать.
Также нет поддержки фоновых задач или прямых загрузок.
Последнее можно сделать вручную, но у него будут те же недостатки, что и у «Скрепки».
Есть еще одно важное замечание.
Получение файлов через сервер изображений (приложение Dragonfly для обработки в процессе загрузки) — это совершенно отдельная обязанность.
Я имею в виду, что вы можете использовать другую библиотеку загрузки файлов, которая включает в себя все необходимое (прямые загрузки, фоновые задачи, различные ORM и т. д.) для загрузки файлов в репозиторий и при этом использовать Dragonfly для обслуживания этих файлов.
map "/attachments" do
run Dragonfly.app # doesn't care how the files were uploaded
end
Атташе
Другой подход к загрузке файловАтташе Относительно новая библиотека, поддерживающая обработку во время загрузки.
Разница между Dragonfly и Refile заключается в том, что Attache был разработан для работы как отдельный сервис, поэтому файлы загружаются и обслуживаются через сервер Attache. Attache имеет интеграцию ActiveRecord для связывания загруженных файлов с записями базы данных и поддерживает прямую загрузку.
Но чего еще не хватает, так это возможности резервного копирования и удаления файлов в фоновых задачах.
Кроме того, Attache недостаточно гибок.
Обратите внимание, что, как и Dragonfly, Attache не нуждается в интеграции с моделью — для этого можно использовать Shrine. В этом году я побывал на RedDotRubyConf в Сингапуре, где у меня была возможность встретиться с автором Attache, и после очень интересной дискуссии о проблемах с загрузкой файлов мы пришли к решению, что было бы полезно использовать Shrine для логики прикрепления файлов.
и просто подключите Attache в качестве бэкэнда.
Таким образом, Attache по-прежнему может делать то, что у него получается лучше всего — обслуживать файлы, но делегировать обработку вложений Shrine.
Окончательно
Поддержка прямых загрузок, фоновое управление файлами, обработка при загрузке и возможность использования с другими ORM — это то, чего я действительно ожидаю от библиотеки.Однако ни одна существующая библиотека не поддерживала все эти требования.
Поэтому я решил создать новую библиотеку Храм , основанный на знаниях из существующих библиотек.
Цель Shrine — не быть корявым, а предоставить функциональность и гибкость, которые позволят оптимизировать различные задачи при работе с файлами.
Это амбициозная цель, но после года интенсивных разработок и исследований я чувствую, что достиг ее.
По крайней мере возможностей больше, чем в любой другой библиотеке для Ruby. В оставшейся части этой серии я познакомлю вас со всеми интересными функциями, которые можно использовать в Shrine, так что следите за обновлениями! Оригинал: Улучшение загрузки файлов с помощью Shrine: мотивация Другие статьи серии в блоге автора: Улучшенная загрузка файлов с помощью Shrine: Uploader Улучшенная загрузка файлов с помощью Shrine: вложение Улучшение загрузки файлов с помощью Shrine: обработка Улучшенная загрузка файлов с помощью Shrine: метаданные Теги: #загрузка файла #загрузка файла #ruby #ruby #ruby onrails
-
Т1 В Деловом Мире
19 Oct, 24 -
Массовая Холакратия
19 Oct, 24