В этом посте я собираюсь показать вам, как создать простой сервер с помощью node.js и выразить, который будет получать любое размещенное изображение и изменять его размер в соответствии с вашими требованиями. Код довольно прост, но стоит отметить логику его реализации. Если вы не хотите создавать свой собственный инструмент для изменения размера изображений и просто хотите использовать наш, см. мой предыдущий пост.

Изменение размера изображения

Начнем с конца. Игнорируя то, как реализован реальный сервер, чтобы изменить размер изображения, нам нужно сначала получить изображение. Так что, возможно, мы напишем такой код (обратите внимание, что это не окончательный ответ)

Далее нам нужно изменить размер изображения. Обратите внимание, что для этого мы используем библиотеку под названием sharp, которая лучше всего работает, если изображение представляет собой буфер.

Проблема с этой логикой заключается в том, что наша программа может потреблять большое количество памяти, если изображение очень большое. Мы выделяем две отдельные переменные для хранения этого изображения. Возможно, у нас закончится место в куче, если трафик на наш сервер увеличится. Чтобы смягчить это, мы будем использовать потоки.

Вместо того, чтобы хранить различные переменные для серии шагов обновления изображения, мы отправляем фрагменты данных на последующие шаги процесса по мере того, как эти данные становятся доступными. Обратите внимание, что это теория того, как должны работать потоки, а не то, как они гарантированно себя ведут. Например, поток может просто передать все данные, как только он будет готов, так что у нас не будет большего успеха, чем в нашей исходной реализации. Лучше всего думать о потоках как об абстракции и останавливаться на этом.

Это намного чище и приятнее для глаз. Как мы увидим в следующем разделе, мы также можем передать результат этого потока прямо в ответ клиенту.

На этом этапе нам нужно начать думать, как использовать этот код на нашем экспресс-сервере. Чтобы этот код работал, нам нужно несколько параметров, чтобы определить, как изображение должно быть обновлено и отправлено обратно пользователю. Для этого мы тщательно разработаем схему URL.

URL-схема

Схема, которую мы используем, выглядит примерно так

/:тип изменения размера/:размер/:редакция/:путь к изображению

Где:

  • :resize-type — [обложка|содержать], как мы должны изменить размер изображения. Это похоже на CSS-атрибут background-size.
  • :размер — [ширина x высота | ширина | x высота] новые размеры изображения.
  • :revision — [любой] этот параметр используется для очистки кеша CDN (см. ниже). Это может быть любое значение, но мне нравится делать это числом.
  • :image-path — [/path/to/image] этот параметр используется для определения URL-адреса запроса для изображения.

Единственное, чего не хватает этому URL-адресу, — это способа узнать корневой домен, на котором размещено изображение (например, example.com). Это значение предоставляется Сетью доставки контента, которую можно использовать в качестве прокси для пересылки любого заголовка запроса на наш сервер. Информацию о том, как это настроить, смотрите в моем предыдущем посте. Причина, по которой мы передаем домен таким образом, проста: это заставляет нас использовать CDN. Ну ладно, может и не принуждает, но всячески поощряет. Не заблуждайтесь, несмотря на любую оптимизацию, которую мы делаем для создания быстрого алгоритма изменения размера изображения, этот процесс очень дорог. Нет причин заставлять сервер дважды изменять размер одного и того же изображения. Использование CDN позволит нам кэшировать изображение с измененным размером на основе его URL-адреса, поэтому, если то же самое изображение будет запрошено снова, мы можем пропустить процесс изменения размера и серверировать изображение с измененным размером непосредственно из кеша. Это имеет решающее значение для масштабируемости. Кроме того, без использования CDN было бы смехотворно легко провести DDOS-атаку на ваш сервер.

Вы ДОЛЖНЫ использовать сеть доставки контента. Вот как это настроить.

Почему бы просто не использовать параметры запроса?

Причина использования такой структуры URL вместо того, чтобы просто добавлять все в кучу параметров запроса, двояка. Во-первых, такой URL намного проще читать. Вторая причина связана с тем, как наша Сеть доставки контента (также известная как AWS CloudFront) кэширует запросы. CDN кэширует запросы на основе полного URL-адреса. Таким образом, если мы сделаем запрос на /images?size=200&type=cover, а затем на следующий запрос на /images?type=cover&size=200, наша CDN сообщит о промахе кеша, поскольку эти два URL-адреса отличаются, хотя для сервера они точно такие же. В итоге,

Порядок параметров строки запроса имеет значение для CDN. В результате мы используем как можно меньше параметров строки запроса.

Имея это в виду, мы можем приступить к созданию нашего экспресс-сервера.

Сервер

Имея в виду нашу схему URL, давайте напишем наши экспресс-маршруты.

Достаточно просто. Быстро, давайте взглянем на промежуточное ПО с двумя валидаторами.

Функция validateRequest распределила обязанности по проверке между тремя различными функциями, используя функцию aysnc.applyEachSeries. Каждая функция проверяет свою часть запроса и сопоставляет все параметры запроса с новым свойством res.props.

Теперь давайте посмотрим на промежуточное ПО для изменения размера.

И это все! Как видите, этот код использует потоки для передачи данных непосредственно из запроса на получение изображения в средство изменения размера, а затем в объект ответа, поэтому у нас нет накладных расходов на использование буферов.

Сделать это немного красивее

Изменение размера изображения — это только начало. Мы можем выполнять любую другую обработку изображений, которую захотим. Давайте посмотрим, как мы можем добавить параметр качества, чтобы уменьшить размер изображения, и параметр размытия.

Вы заметите, что мы сохраняем параметры размытия и качества в виде строки запроса. Хотя строки запроса не идеальны по причинам, описанным выше, мы не хотим делать схему URL слишком непослушной, поэтому для простоты используем строки запроса.

Вы можете добавить в программу изменения размера изображения столько дополнительных функций, сколько захотите, но это неплохое начало.

В следующем посте я покажу вам, как создать изоморфный компонент реакции, который позволит вам создать компонент с пользовательским интерфейсом, подобным тому, который можно увидеть на Medium, во время загрузки изображения.