Подтвердить что ты не робот

Служебные файлы, хранящиеся в S3 в приложении express/nodejs

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

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

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

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

4b9b3361

Ответ 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.