Загрузка файла в S3 непосредственно из браузера с последующим сохранением URL-адреса в базе данных - более сложный процесс, чем простая обработка всего на стороне сервера. Здесь я буду реализовывать процесс с помощью API-интерфейса Fetch на основе Promise в сочетании с библиотекой AWS-SDK и серверной частью Node / Express.

Поскольку Fetch и ES6 Promises реализованы не во всех браузерах, нам понадобится пара вещей.

npm i -S isomorphic-fetch es6-promise

Начнем с импорта этих зависимостей во интерфейсный модуль для наших запросов S3. Здесь я буду использовать синтаксис импорта и экспорта ES6.

Когда пользователь нажимает кнопку отправки, нам нужна ссылка на наш файл. Я использую ввод файла HTML5 с id # file-input, поэтому любые файлы будут в массиве на объекте ввода. Я могу получить такой файл внутри любого обработчика отправки, с которым я работаю:

К сожалению, у нас нет доступа к нашему идентификатору доступа или ключу AWS на интерфейсе. Хотя мы можем безопасно извлекать их с помощью переменных среды, когда мы работаем на сервере, безопасно хранить эти данные в браузере невозможно. Вместо этого мы можем сделать запрос на наш сервер, чтобы получить «подписанный запрос». Сервер может использовать AWS-SDK для создания URL-адреса запроса, содержащего подпись, с использованием нашего ключа доступа. С помощью этого URL-адреса мы можем отправить наш файл на S3, не рассердив амазонских богов.

Чтобы получить подписанный запрос от нашего сервера, мы передадим наш файл в следующую функцию:

Замените serverUrl фактическим URL-адресом сервера и обратите внимание, что мы достигаем конечной точки с именем / sign-s3. Далее мы реализуем это как экспресс-маршрут, но сначала нам понадобится AWS-SDK.

npm i -S aws-sdk

Теперь мы можем использовать метод SDK getSignedUrl для генерации подписанной строки запроса внутри нашего маршрута. AWS-SDK достаточно умен, чтобы находить необходимые переменные среды внутри файла dotenv, но вам все равно нужно будет указать имя сегмента.

Во-первых, мы берем имя файла и тип из строки запроса. Если вы хотите хешировать свое имя файла, чтобы избежать конфликтов имен в корзине, это было бы место для этого. Затем мы настраиваем объект конфигурации для передачи в метод AWS-SDK. Этот метод принимает функцию обратного вызова, и мы собираемся сказать ему, чтобы он возвращал ответ JSON с необходимыми данными, а также URL-адрес файла, который мы в конечном итоге сохраним в нашей базе данных.

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

Теперь у нас есть все необходимое для загрузки изображения. Вернемся к нашему интерфейсному модулю!

Эта функция возьмет файл вместе с подписанным запросом и URL-адресом файла из ответа JSON нашего сервера и создаст запрос PUT для S3. Помните, что подписанный запрос - это просто строка URL-адреса, содержащая подпись, поэтому она служит первым аргументом для выборки. Теперь свяжем две части вместе:

Эта функция сначала вызывает нашу функцию getSignedRequest, которая возвращает обещание, которое разрешается с ответом сервера JSON. Затем мы передаем этот JSON в нашу функцию uploadFile, которая возвращает обещание, которое разрешается с URL-адресом, который мы хотим сохранить в нашей базе данных. Если что-то пойдет не так, мы просто печатаем ошибку и вместо этого возвращаем null.

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