Служебные файлы, хранящиеся в S3 в приложении express/nodejs
У меня есть приложение, где пользовательские фотографии являются частными. Я храню фотографии (также миниатюры) в AWS s3. На сайте есть страница, на которой пользователь может просматривать свои фотографии (например, миниатюры). Теперь моя проблема в том, как я могу обслуживать эти файлы. Некоторые параметры, которые я оценил, следующие:
- Работа с файлами с CloudFront (или AWS) с использованием подписанного поколения URL-адресов. Но проблема в том, что каждый раз, когда пользователь обновляет страницу, я должен снова создать так много подписанных URL-адресов и загрузить их. Поэтому я не смогу кэшировать изображения в браузере, что было бы хорошим выбором. Есть все равно, чтобы сделать все еще в javascript? Я не могу иметь верность этих URL-адресов дольше из-за проблем с безопасностью. И во-вторых, в течение этого периода времени, если кто-то завладел этим URL-адресом, он может просмотреть файл без проверки подлинности из приложения.
- Другой вариант - передать файл из моего экспресс-приложения после его потоковой передачи с серверов S3. Это позволяет мне иметь HTTP-заголовки кэша, поэтому включить кеширование браузера. Он также гарантирует, что никто не может просматривать файл без проверки подлинности. В идеале я хотел бы передать файл, и я хостинг, используя NGINX-прокси-ретранслятор, передающий другую сторону в NGINX. Но, как я вижу, это возможно только в том случае, если файл существует в тех же системных файлах. Но здесь я должен передать его и вернуться, когда я получу поток. Не хотите хранить файлы локально.
Я не могу оценить, какой из двух вариантов будет лучшим выбором? Я хочу перенаправить как можно большую работу на S3 или облачную область, но даже с использованием поддельных URL-адресов также делает запрос первым на моих серверах. Я также хочу использовать функции кэширования.
Итак, что было бы идеальным способом? с ответами на конкретные вопросы, относящиеся к этим методам?
Ответы
Ответ 1
я просто вытолкнул бы его из S3. это очень просто, а подписанные URL-адреса намного сложнее. просто убедитесь, что вы устанавливаете заголовки content-type
и content-length
при загрузке изображений на S3.
var aws = require('knox').createClient({
key: '',
secret: '',
bucket: ''
})
app.get('/image/:id', function (req, res, next) {
if (!req.user.is.authenticated) {
var err = new Error()
err.status = 403
next(err)
return
}
aws.get('/image/' + req.params.id)
.on('error', next)
.on('response', function (resp) {
if (resp.statusCode !== 200) {
var err = new Error()
err.status = 404
next(err)
return
}
res.setHeader('Content-Length', resp.headers['content-length'])
res.setHeader('Content-Type', resp.headers['content-type'])
// cache-control?
// etag?
// last-modified?
// expires?
if (req.fresh) {
res.statusCode = 304
res.end()
return
}
if (req.method === 'HEAD') {
res.statusCode = 200
res.end()
return
}
resp.pipe(res)
})
})
Ответ 2
Если вы перенаправите пользователя на подписанный URL с помощью 302 Found
, браузер будет кэшировать результирующее изображение в соответствии с его заголовком cache-control
и не будет запрашивать его во второй раз.
Чтобы браузер не кэшировал подписанный URL-адрес, вы должны отправить соответствующий cache-control
заголовок вместе с ним:
Cache-Control: private, no-cache, no-store, must-revalidate
Итак, в следующий раз он отправит запрос на исходный URL-адрес и будет перенаправлен на новый подписанный URL-адрес.
Вы можете создать подписанный URL с knox
с помощью signedUrl
method.
Но не забудьте установить соответствующие заголовки для каждого загруженного изображения. Я бы рекомендовал использовать заголовки cache-control
и Expires
, потому что у некоторых браузеров нет поддержки заголовка cache-control
, а Expires
позволяет установить только абсолютное время истечения срока действия.
Во втором варианте (потоковое изображение через приложение) вы сможете лучше контролировать ситуацию. Например, вы сможете генерировать заголовок Expires
для каждого ответа в соответствии с текущей датой и временем.
Но как насчет скорости? Использование подписанных URL-адресов имеет два преимущества, которые могут повлиять на скорость загрузки страницы.
Во-первых, вы не будете перегружать ваш сервер. Создание подписанных URL-адресов, если это быстро, потому что вы просто хешируете свои учетные данные AWS. И для потоковой передачи изображений через ваш сервер вам нужно будет поддерживать множество дополнительных подключений во время загрузки страницы. В любом случае, это не будет иметь никакого реального значения, если ваш сервер не загружен.
Во-вторых, браузеры поддерживают только два параллельных соединения для имени хоста во время загрузки страницы. Таким образом, браузер будет поддерживать одновременное разрешение URL-адресов при их загрузке. Он также сохранит загрузку изображений с блокировки загрузки любых других ресурсов.
В любом случае, чтобы быть абсолютно уверенным, вы должны запустить некоторые тесты. Мой ответ основывался на моем знании спецификации HTTP и моем опыте в веб-разработке, но я никогда не пытался служить изображениям таким образом самостоятельно. Обслуживание общедоступных изображений с длительным сроком службы кеша непосредственно с S3 увеличивает скорость страницы, я считаю, что ситуация не изменится, если вы сделаете это с помощью перенаправления.
И вы должны иметь в виду, что потоковые изображения через ваш сервер принесут все преимущества Amazon CloudFront к нулю. Но пока вы обслуживаете контент непосредственно из S3, оба варианта будут работать нормально.
Таким образом, есть два случая, когда использование подписанных URL-адресов должно ускорить вашу страницу:
- Если у вас много изображений на одной странице.
- Если вы используете изображения с помощью CloudFront.
Если на каждой странице есть только несколько изображений и их непосредственное использование с S3, вы, вероятно, не увидите никакой разницы.
Важное обновление
Я провел несколько тестов и обнаружил, что я ошибся в кешировании. Это правда, что браузеры кэшируют изображения, к которым они были перенаправлены. Но он связывает кэшированное изображение с URL-адресом, на который он был перенаправлен, а не с оригинальным. Таким образом, когда браузер второй раз загружает страницу, он снова запрашивает изображение с сервера, а не извлекает его из кеша. Конечно, если сервер отвечает с тем же адресом перенаправления, который он ответил в первый раз, браузер будет использовать свой кеш, но это не относится к подписанным URL-адресам.
Я обнаружил, что заставляя браузер кэшировать подписанный URL-адрес, а также данные, которые он получает, решает проблему. Но мне не нравится идея кэширования неверного URL-адреса переадресации. Я имею в виду, что если браузер будет пропускать изображение, он попытается снова запросить его, используя недопустимый подписанный url из кеша. Итак, я думаю, что это не вариант.
И неважно, если CloudFront будет работать с изображениями быстрее или если браузеры ограничивают количество параллельных загрузок для имени хоста, преимущество использования кеша браузера превосходит все недостатки изображений каналов через ваш сервер.
И похоже, что большинство социальных сетей решает проблему с частными изображениями, скрывая свои фактические URL-адреса за некоторыми частными прокси. Таким образом, они хранят весь свой контент на общедоступных серверах, но нет способа получить URL-адрес для частного изображения без авторизации. Конечно, если вы откроете личное изображение на новой вкладке и отправьте URL-адрес своему другу, он также сможет увидеть изображение. Итак, если это не вариант для вас, вам будет лучше использовать решение Джонатана Онга.
Ответ 3
Я хотел бы использовать параметр CloudFront, если фотографии действительно должны оставаться закрытыми. Похоже, у вас будет гораздо больше гибкости при администрировании собственной политики безопасности. Я думаю, что настройка nginx может быть более сложной, чем это необходимо. Экспресс должен давать вам очень хорошую производительность, работая как удаленный прокси-сервер, где он использует запрос для извлечения элементов из S3 и передает их авторизованным пользователям. Я настоятельно рекомендую взглянуть на Asset Rack, который использует хеш-подписи, чтобы обеспечить постоянное кэширование в браузере. Вы не сможете использовать стандартные стойки, потому что вам нужно вычислить MD5 каждого файла (возможно, при загрузке?), Который вы не можете сделать при потоковой передаче. Но в зависимости от вашего приложения это может сэкономить вам много усилий, чтобы браузеры никогда не нуждались в повторной настройке изображений.
Ответ 4
Что касается второго варианта, вы можете установить заголовки управления кешем непосредственно в S3.
Относительно вашего первого варианта. Считаете ли вы, что ваши изображения выглядят иначе?
Когда вы храните изображение на S3, не могли бы вы использовать хэшированное и рандомизированное имя файла? Было бы довольно сложно сделать так, чтобы имя файла было сложно угадать +, таким образом у вас не будет проблем с производительностью при просмотре изображений.
Это технология использования Facebook. Вы можете просмотреть изображение, когда вы выходите из системы, если вы знаете URL.