По следам недавней статьи об изменении размеров изображений на сервере, я решил поделиться опытом внедрения модуля ImageResizer для IIS. Конечно написать простой обзор было бы слишком скучно, но мы не ограничились простым внедрением модуля.
Итак, у нас в распоряжении был купленный ImageResizer + набор плагинов Cloud Bundle для работы с облаками.
К сожалению мне запрещено называть проекты, в которых внедрено данное решение, но я могу обрисовать суть. Это новостные порталы ориентированные на северную америку. На сайте представлены статьи и видео ролики.
Статьи хранятся в БД, редактор может прикрепить к статье заглавную картинку. Изображение хранится в Amazon S3. Как Вы понимаете, редактор может загрузить изображение как маленькое, так и огромное и при этом нельзя терять оригинал.
Видео файлы загружаются, обрабатываются и хранятся в облачном хранилище видео BrightCove. После загрузки видео в хранилище, оно всячески обрабатывается, перекодируется в несколько потоков разного формата и для видео автоматически выбирается миниатюра (thumbnail).
Естественно, раз все это происходит в облаке, то и картинка хранится в облаке, а мы получаем прямую ссылку для вставки. Но и тут картинка не всегда может соответствовать требуемому размеру.
Итого мы имеем набор изображений в Amazon S3, набор изображений в BrightCove и все изображения нужно уметь быстро отдавать уже подогнанными под нужный размер. Кроме того, в разных частях сайта могут использоваться различные размеры изображений. При этом набора плагинов для кеширования у нас не было, зато у нас был CloudFront.
Как ни странно, товарищ bitmap в своей статье не упомянул, как именно он изменяет размер изображения, ибо есть множество способов (муки выяснения необходимого варианта с заказчиком Вы можете лицезреть на фото). Можно растягивать в рамку, получая растянутые лица, можно сохранять пропорции и заполнять освободившееся пространство цветом. Можно сохранять пропорции и обрезать края. Модуль также позволяет еще кучу не нужных нам рюшечек, типа наложения фильтров и прочего. В итоге, на одном проекте мы стали растягивать аналогично растягиванию css, а на другом проекте заполнение цветом.
Стандартный сценарий
По умолчанию из коробки предполагается что изображения и IIS расположены на одном сервере и изменение размеров осуществляется простым добавлением параметров к ссылке:
/image.jpg?height=200&width=300
или
/image.jpg?h=200&w=300
.
Отлично, но как забрать изображения из Amazon S3?
S3 Reader
Тут нам на помощь приходит первый из набора плагинов Cloud Bundle: S3 Reader. Путем нехитрых настроек web.config, он позволяет использовать ссылку следующего формата:
/s3/bucket/folder/image.jpg?h=200&w=300
RemoteReader plugin
Ок, теперь мы можем отдавать картинки из S3, но S3 это довольно популярная вещь, как насчет совершенно стороннего сервера? Здесь включается RemoteReader plugin. Тут уже не все так просто. Конечная ссылка имеет следующий формат:
/remote.jpg.ashx?w=200&height=300&urlb64=45b45c4a2099b...&hmac=a2099ba2099b
.
Где remote.jpg.ashx это конечная точка для перехвата ссылки модулем, параметр urlb64 — это нехитро зашифрованная при помощи HMAC SHA-256 конечная ссылка на удаленный сервер с картинкой. Данную ссылку генерирует специальный метод:
RemoteReaderPlugin.Current.CreateSignedUrl("http://remote.com/image.jpg");
CloudFront
Ок, с основной задачей мы справились. Теперь нужно как-то кешировать результат, иначе быстро все это работать не будет.
Кеширующих плагинов у нас нет, зато есть такая волшебная вещь, как CloudFront custom origin. Мы создали новую дистрибуцию CloudFront, указывающую на наш домен. Так что теперь у нас есть ссылки формата:
httр://my-distribution-name.cloudfront.com/remote.jpg.ashx?w=200&height=300&urlb64=45b45c4a2099b...&hmac=a2099ba2099b
и
httр://my-distribution-name.cloudfront.com/s3/bucket/folder/image.jpg?h=200&w=300
Но теперь наш сайт стал открываться по адресу httр://my-distribution-name.cloudfront.com, забивая cloudfront. Тогда мы быстро добавили раздел для картинок. И CloudFront со ссылки
httр://my-distribution-name.cloudfront.com/s3/bucket/folder/image.jpg?h=200&w=300
cтал перенаправлять запрос на
httр://my-site.com/images/s3/bucket/folder/image.jpg?h=200&w=300
Вроде бы вся должно работать, но внезапно выяснилось, что CloudFront нещадно рубит длинные строки параметров и мы получили тонны ошибок и не открывающихся картинок. Тут нам помог CloudFront plugin, позволивший преобразовать ссылки к следующему формату:
httр://my-distribution-name.cloudfront.com/remote.jpg.ashx;w=200;height=300;urlb64=45b45c4a2099b...;hmac=a2099ba2099b
и
httр://my-distribution-name.cloudfront.com/s3/bucket/folder/image.jpg;h=200;w=300
Короткие ссылки
Все это отлично работало, но инженерная мысль пошла еще дальше. Что если кто-то начнет генерировать не нужные нам разрешения картинок? Максимальный размер увеличения конечно ограничен, но все равно так можно заDDOSить сайт, да еще и полученные картинки разнесутся по сотням серверов CloudFront по всему миру. Ну и конечно длина ссылки просто ужасна. Тогда мы решили реализовать функционал коротких ссылок.
При генерации ссылки мы складываем в базу полученную длинную ссылку вида:
/remote.jpg.ashx;w=200;height=300;urlb64=45b45c4a2099b...;hmac=a2099ba2099b
и получаем её id в таблице. В вёрстку же выплевываем ссылку формата:
httр://my-distribution-name.cloudfront.com/42
CloudFront обращается к нам по адресу:
httр://my-site.com/i/42
Мы перехватываем запрос, выбираем длинную ссылку по ключу 42 из БД, в серверном коде делаем HttpRequest к самому себе, чтобы его перехватил ImageResizer и в ответ выдаем результат его работы. CloudFront складывает полученную картинку на своих серверах и больше мы не получаем этот запрос до следующей инвалидации кеша.
И последний штрих это сокрытие страшного префикса CloudFront ссылки, представляющей собой беспорядочный набор цифр и букв, что тоже не очень красиво, при помощи дополнительного домена.
В итоге конечная для пользователя ссылка имеет вид:
httр://short.com/42
При этом изображение закешировано, легко доступно с ближайшего к пользователю сервера, злобный хакер не может самостоятельно изменить размер, заDDOSив наш модуль, мы имеем короткую ссылку и самое главное все картинки с нужными размерами красиво смотрятся на своих местах.
Заключение
В заключение хочу сказать, что плагин прекрасно работает, имеет кучу различных настроек и плагинов на все случаи жизни, имеет режим отладки на случай непредвиденных ситуаций. Автор отвечает при обращении по проблемам и даже вроде бы платит за найденные баги. Конечно, модуль платный, но он того стоит.
Автор: ST-bobr