ユーザーの写真を非公開にするアプリがあります。写真(サムネイルも)をAWSs3に保存します。ユーザーが自分の写真(サムネイルなど)を表示できるページがサイトにあります。今私の問題は、これらのファイルをどのように提供するかです。私が評価したいくつかのオプションは次のとおりです。
2つのオプションのどちらがより良い選択であるかを評価することができませんか?できるだけ多くの作業をS3またはクラウドフロントにリダイレクトしたいのですが、シンギングされたURLを使用しても、最初にサーバーにリクエストが送信されます。キャッシュ機能も必要です。
では、理想的な方法は何でしょうか。それらの方法に関連する特定の質問に対する答えがありますか?
s3からストリーミングするだけです。それは非常に簡単で、署名されたURLははるかに困難です。画像をS3にアップロードするときは、必ずcontent-type
ヘッダーとcontent-length
ヘッダーを設定してください。
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)
})
})
302 Found
ブラウザを使用してユーザーを署名付きURLにリダイレクトする場合、ブラウザはcache-control
ヘッダーに従って結果の画像をキャッシュし、2回目は要求しません。
ブラウザが署名されたURL自体をキャッシュしないようにするには、適切なCache-Control
ヘッダーを一緒に送信する必要があります。
Cache-Control: private, no-cache, no-store, must-revalidate
そのため、次回は元のURLにリクエストを送信し、新しい署名付きURLにリダイレクトされます。
knox
method を使用して、signedUrl
で署名付きURLを生成できます。
ただし、アップロードされたすべての画像に適切なヘッダーを設定することを忘れないでください。一部のブラウザはCache-Control
ヘッダーをサポートしておらず、Expires
では絶対有効期限のみを設定できるため、Cache-Control
ヘッダーとExpires
ヘッダーの両方を使用することをお勧めします時間。
2番目のオプション(アプリを介して画像をストリーミングする)を使用すると、状況をより適切に制御できます。たとえば、現在の日付と時刻に従って、応答ごとにExpires
ヘッダーを生成できます。
しかし、速度はどうですか?署名付きURLを使用すると、ページの読み込み速度に影響を与える可能性のある2つの利点があります。
まず、サーバーに過負荷をかけません。 AWS認証情報をハッシュしているだけなので、高速であれば署名付きURLを生成します。また、サーバーを介して画像をストリーミングするには、ページの読み込み中に多くの追加の接続を維持する必要があります。とにかく、サーバーがハードロードされていない限り、実際の違いはありません。
次に、ブラウザは、ページの読み込み中にホスト名ごとに2つの並列接続のみを保持します。そのため、ブラウザは画像のURLをダウンロードしている間、並行して解決し続けます。また、画像のダウンロードが他のリソースのダウンロードをブロックしないようにします。
とにかく、絶対に確実にいくつかのベンチマークを実行する必要があります。私の答えは、HTTP仕様に関する知識と、Web開発の経験に基づいていましたが、自分でそのように画像を提供しようとしたことはありませんでした。キャッシュの有効期間が長いパブリックイメージをS3から直接提供すると、ページ速度が向上します。リダイレクトを介して提供しても状況は変わらないと思います。
また、サーバーを介して画像をストリーミングすると、AmazonCloudFrontのすべてのメリットが失われることを覚えておく必要があります。ただし、S3から直接コンテンツを提供している限り、どちらのオプションでも問題なく機能します。
したがって、署名付きURLを使用するとページが高速化される場合が2つあります。
各ページに画像がほとんどなく、S3から直接提供している場合は、おそらくまったく違いは見られません。
いくつかのテストを実行したところ、キャッシュについて間違っていることがわかりました。ブラウザがリダイレクト先の画像をキャッシュするのは事実です。ただし、キャッシュされた画像は、元の画像ではなく、リダイレクト先のURLに関連付けられます。そのため、ブラウザが2回目にページを読み込むと、キャッシュから画像を取得するのではなく、サーバーに画像を再度要求します。もちろん、サーバーが最初に応答したのと同じリダイレクトURLで応答した場合、ブラウザーはそのキャッシュを使用しますが、署名されたURLの場合はそうではありません。
署名されたURLと受信したデータをブラウザにキャッシュさせることで、問題が解決することがわかりました。しかし、無効なリダイレクトURLをキャッシュするという考えは好きではありません。つまり、ブラウザが何らかの理由で画像を見逃した場合、キャッシュから無効な署名付きURLを使用して画像を再度要求しようとします。だから、それは選択肢ではないと思います。
また、CloudFrontがイメージをより速く提供するかどうか、またはブラウザーがホスト名ごとの並列ダウンロードの数を制限するかどうかは関係ありません。ブラウザーキャッシュを使用する利点は、サーバーを介してイメージをパイプすることのすべての欠点を上回ります。
また、ほとんどのソーシャルネットワークは、実際のURLを一部のプライベートプロキシの背後に隠すことで、プライベート画像の問題を解決しているようです。そのため、すべてのコンテンツをパブリックサーバーに保存しますが、許可なくプライベートイメージへのURLを取得する方法はありません。もちろん、新しいタブでプライベート画像を開いてURLを友達に送信すると、友達もその画像を見ることができます。したがって、それが選択肢ではない場合は、 Jonathan Ongのソリューション を使用するのが最善です。
写真を本当に非公開にする必要がある場合は、CloudFrontオプションの使用に関心があります。独自のセキュリティポリシーを管理する際の柔軟性が大幅に向上するようです。 nginxのセットアップは必要以上に複雑かもしれないと思います。 Expressは、リクエストを使用してS3からアイテムをフェッチし、承認されたユーザーにストリーミングするリモートプロキシとして機能する非常に優れたパフォーマンスを提供するはずです。ハッシュ署名を使用してブラウザで永続的なキャッシュを有効にするAssetRackを確認することを強くお勧めします。各ファイルのMD5を計算する必要があるため(おそらくアップロード時に)、デフォルトのラックを使用することはできません。これは、ストリーミング時には実行できません。ただし、アプリケーションによっては、ブラウザが画像を再フェッチする必要がないため、多くの労力を節約できます。
2番目のオプションに関しては、 S3に直接キャッシュ制御ヘッダー を設定できるはずです。
あなたの最初のオプションについて。別の方法で画像を保護することを検討しましたか? S3に画像を保存する場合、ハッシュ化およびランダム化されたファイル名を使用できませんでしたか?ファイル名を推測しにくくするのは非常に簡単です+この方法では、画像を表示し直すときにパフォーマンスの問題が発生しません。
これはFacebookが使用するテクニックです。 URLを知っている限り、ログアウトしても画像を表示できます。