Загрузка картинок на сервер из админки для фронта?
Дорогие хабровчане!
Сломал голову, ничего интересного придумать не могу.
Немного предыстории: лабаю сайты, разработал для этого небольшой фреймворк. пишу на asp.net mvc и обычно для админки делаю отдельную Area. При такой организации проекта, всё ок, загружаю файлы в отдельную папку (напр. ~/content/images/), та часть, которая ответственна за фронт, свободно обращается к файлам из этой папки, никаких трудностей. Причём написал хелпер, который генерирует картинку требуемых размеров непосредственно при обращении к ней. Это выглядит приблизительно так:
@Html.ImageFor(Model.Image, 150, 250)
Недавно решил разнести админку и фронт по разным проектам, чтобы иметь возможность раскидать их по разным доменам. Вот тут начались проблемы. Куда и как мне грузить файлы? размышлял над такими вариантами:
1) просто бросить в папку в админке, с фронта обращаться в неё. Вариант не нравится, потому что не хочу чтобы пользователь знал о домене админки.
2) написать сервис, который расположить на фронте, сохраняет файлы в папку на своём домене. Как бы вариант неплох, можно сделать реализацию сервиса, которая бы сохраняла файлы где-нибудь в облаке. И вот всё бы хорошо, но как быть тогда с размерами? Ведь при такой реализации я не могу генерировать картинки нужного размера.
3) предыдущий пункт + задавать размеры картинок заранее, в настройках сайта. в этом случае я теряю гибкость при вёрстке. То есть верстальщик кроме того, что должен заранее знать какие картинки и каких размеров должны быть, так ещё и должен лезть куда-то ещё и указывать эти размеры.
В общем я в большой растерянности и очень надеюсь на ваш мудрый совет.
уточню: я склоняюсь именно ко второму варианту, то есть мой сервис может находиться вообще чёрт знает где, на третьем сервере. Сервис сам знает куда сохранять, в базу пишет полный урл к файлу. Опять же, иногда нужна загрузка файлов и с фронта. и при таком подходе у меня будет единая реализация загрузки (и для админки и для фронта).
главная проблема в генерации картинок при вёрстке. то есть при моём текущем подходе я получаю урл к файлу с необходимыми мне размерами. чего я не могу сделать при использовании сервиса. поэтому у меня и появились мысли, выраженные в третьем варианте, который мне не нравится. Но это пока лучшее что я смог придумать.
1) Не совсем понятно зачем вам вообще генерировать картинки нужного размера в момент обращения к ним. Обычно все варианты картинок генерируются в момент загрузки.
2) Если все же вам так удобнее, в любом случае в том месте где вы будите хранить картинки (и формировать их налету) вам придется писать некий код-предобработчик. Например, Nginx сначала пытается получить ассет, а если не находит, то передает управление программной части, которая и занимается формированием и сохранением картинки. Сразу после первого обращения к картинке она будет создана и Nginx будет сразу отправлять ее клиенту как готовый ассет, не передавая больше управление скрипту.
3) Никаких проблем с расшариванием изображений быть не может. В БД хранится только путь к ассету. Например /public/pics/flower.png. Поскольку вы сами программируете систему, как и на фронте, так и на бэке вы легко можете в константах задать конкретный путь к вашему CDN + установить свои правила формирования имен картинок.
Например:
В базе хранится только
/public/pics/flower_original.png
А дальше можно формировать на основе этого базового урла что угодно.
Проблема в обработке картинок. Как сгенерировать картинку нужных мне размеров, чтобы это происходило во время вёрстки? ну и потом при обработке пользовательских файлов.
Гипотетическая ситуация: пользователь загружает фотографию размером 6000 на 8000 px. При сохранении я формирую изображение каких-то приемлемых размеров, скажем 1500 на 2000 px, но для вывода превьюх я хочу выводить картинки размером 150 на 200, а при выводе в сайдбаре ещё какой то размер. Всего сразу же не предусмотришь, поэтому у меня они генерируются при первом обращении и сохраняются, потому уже сразу берётся прямой урл, исходя из требуемых размеров изображения.
Если проецировать текущую реализацию на то что я хочу, то мне, чтобы определить надо ли сгенерировать файл, нужно проверить есть ли такой файл по такому то урлу (раньше я проверял файл в папке), и если нет, то скачать исходный, сделать новый, скормить новый сервису сохранения картинок. Но это бред конечно же.
Есть ещё такая идея: хранить в базе урлы ко всем сгенерированным размерам. Но как-то мне это не кажется нормальным.
Напишу подробнее:
Пункт 1. Может так и делают обычно, но тот вариант, который использую я сейчас, позволяет не заморачиваться во время программинга сайта, по поводу размероы нужных при вёрстке. Повторюсь, картинка генерируется 1 раз, потом путь к ней формируется из требуемых размеров.
Пункт 2. Этот пункт мне сначала и понравился. Но по факту это получается тот же самый гет-запрос. То есть потенциальный «злоумышленник» может запустить кучу запросов для разных размеров картинок, замучав таким образом мой сервер. В моём текущем варианте, генерируются картинки только те, которые указаны в шаблоне при вёрстке. Файл физически существует при отображении страницы.
Пункт 3. С этим проблем нет, указать путь и правило формирования файла — не проблема. Задача в том, чтобы при формировании этого имени, файл уже был создан, а не создавался по запросу.
Вот именно поэтому я и подумал сохранять размеры так же в базе. Поясню. Раньше (то есть сейчас) я сохранял файл на диск и при формировании урла я смотрел, есть ли такой файл или нет (по сгенерированному имени). Сейчас (то есть для будущей версии фреймворка) я должен проверять это наличие неизвестно где (где-то на третьем сервере), что очень неудобно и долго. Поэтому, единственное что я смог придумать, проверять в базе, если в базе нет записи, то и файла нет. Генерирую файл, сохраняю, получаю урл, записываю его в базу. Поскольку операция единократная, то такой подход меня устроил бы. Но, кмк и как вы выразились, «Хранить в базе урлы ко всем вариантам картинок — это бред.».
Конечно второй пункт, как вариант, пусть и он занимается ресайзом, и стоит постмотреть на wiki.nginx.org/HttpImageFilterModule — мне вполне хватает его, сам nginx и занимается ресайзом, кропом и кешированием картинок.