2013-07-07 2 views
19

У меня есть приложение, где фотографии пользователя являются частными. Я храню фотографии (также миниатюры) в AWS s3. На сайте есть страница, на которой пользователь может просматривать свои фотографии (например, миниатюры). Теперь моя проблема в том, как я могу обслуживать эти файлы. Некоторые параметры, которые я оценил, являются следующими:Служебные файлы, хранящиеся в S3 в приложении express/nodejs

  • Обслуживание файлов с CloudFront (или AWS) с использованием подписанного поколения URL-адресов. Но проблема в том, что каждый раз, когда пользователь обновляет страницу, я должен снова создать так много подписанных URL-адресов и загрузить их. Поэтому я не смогу кэшировать изображения в браузере, что было бы хорошим выбором. Есть все равно, чтобы сделать все еще в javascript? Я не могу иметь верность этих URL-адресов дольше из-за проблем с безопасностью. А во-вторых, в течение этого периода времени, если кто-то завладел этим URL-адресом, он может просмотреть файл без проверки подлинности из приложения.
  • Другой вариант - передать файл из моего экспресс-приложения непосредственно после его потоковой передачи с серверов S3. Это позволяет мне иметь HTTP-заголовки кэша, поэтому включить кеширование браузера. Он также гарантирует, что никто не может просматривать файл без проверки подлинности. В идеале я хотел бы передать файл, и я хостинг, используя NGINX-прокси-ретранслятор, передающий другую сторону в NGINX. Но, как я вижу, это возможно только в том случае, если файл существует в файлах одной и той же системы. Но здесь я должен передать его и вернуться, когда я получу поток. Не хотите хранить файлы локально.

Я не могу оценить, какой из двух вариантов будет лучшим выбором? Я хочу перенаправить как можно большую работу на S3 или облачную область, но даже с использованием поддельных URL-адресов также делает запрос первым на моих серверах. Я также хочу использовать функции кэширования.

Итак, что было бы идеальным способом? с ответами на конкретные вопросы, относящиеся к этим методам?

ответ

19

Я бы просто передал его с 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) 
    }) 
}) 
+1

Пойду с ответом для примера. Большое спасибо. Но если вы не возражаете, можете ли вы помочь мне с чем-то еще. Использование AWS-SDK лучше или knox? –

+1

Никогда не пробовал aws-sdk. Тем не менее, поддерживающие Нокс больше связаны с сообществом узлов. –

+1

Однако ?? Вы же не сказали, что? –

1

Я был бы заинтересован в использовании опции CloudFront, если фотографии действительно должны оставаться закрытыми. Похоже, у вас будет гораздо больше гибкости при администрировании собственной политики безопасности. Я думаю, что настройка nginx может быть более сложной, чем это необходимо. Экспресс должен давать вам очень хорошую производительность, работая как удаленный прокси-сервер, где он использует запрос для извлечения элементов из S3 и передает их авторизованным пользователям. Я настоятельно рекомендую взглянуть на Asset Rack, который использует хеш-подписи, чтобы обеспечить постоянное кэширование в браузере. Вы не сможете использовать стойки по умолчанию, потому что вам нужно вычислить MD5 каждого файла (возможно, при загрузке?), Который вы не можете сделать, когда он работает. Но в зависимости от вашего приложения, это может сэкономить вам много усилий, чтобы браузеры никогда не нуждались в повторной настройке изображений.

+0

Что делать, если я не перекачиваю фотографии, скорее жду, когда файл будет загружен в буфер, а затем вернет его пользователю? –

+1

Когда вы получаете файл, отпечатайте его с помощью того же MD5-хэша, что и для стойки ресурса: https://github.com/techpines/asset-rack/blob/master/lib/asset.coffee#L200. Загрузите в S3, используя это имя файла с knox. Затем, когда пользователь запрашивает файл, используйте для проверки подлинности каждый аут или паспорт, и в случае успеха используйте knox для извлечения файла из S3 и подайте его пользователю, при этом кеш-контроль установлен на кеширование на 1 год, , – dankohn

+0

Да ... Ваша идея выглядит великолепно, но почему я должен носок, тогда как я могу использовать AWS-SDK для этого. –

0

Что касается второго варианта, вы должны быть в состоянии установить cache control headers directly in S3.

Что касается вашего первого варианта. Считаете ли вы, что ваши изображения выглядят иначе? Когда вы храните изображение в S3, не могли бы вы использовать хэшированное и рандомизированное имя файла? Было бы довольно сложно сделать так, чтобы имя файла было сложно угадать +, таким образом у вас не будет проблем с производительностью при просмотре изображений.

Это технология использования Facebook. Вы можете просмотреть изображение, когда вы выходите из системы, если вы знаете URL.

+0

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

+0

понял, я опубликовал еще один вариант –

+0

Где вы разместили другой вариант? Если вы имеете в виду технику facebook, то я уже дал вам знать, что я не вижу, чтобы URL-адрес мог просматривать изображения, если у него нет прав. –

7

Если вы будете перенаправлены пользователю подписанного 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-адреса переадресации. Я имею в виду, что если браузер будет пропускать изображение, он попытается снова запросить его, используя недопустимый подписанный url из кеша. Поэтому я думаю, что это не вариант.

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

И похоже, что большинство социальных сетей решает проблему с частными изображениями, скрывая свои фактические URL-адреса за некоторыми частными прокси. Таким образом, они хранят весь свой контент на общедоступных серверах, но нет способа получить URL-адрес для частного изображения без авторизации. Конечно, если вы откроете личное изображение на новой вкладке и отправьте URL-адрес своему другу, он также сможет увидеть изображение. Итак, если это не вариант для вас, вам будет лучше использовать Jonathan Ong's solution.

+0

Вы уверены, что это будет медленнее, чем генерация signedUrl и перенаправление на него? Медленнее в отношении того, что вы можете указать? –

+0

@SaranshMohapatra Я обновил свой ответ. –

+0

Хорошо Спасибо за ваш ответ. И я сравню результаты и вернусь к вам. Чтобы это было полезно для других. И ваш ответ - самый описательный, который я нашел, так что спасибо снова. –