[英]S3, Signed-URLs and Caching
我正在使用 knox nodejs-library 在我的 webapp (nodejs) 上生成簽名的 url。 但是問題出現了,對於每個請求,我需要為當前用戶重新生成一個唯一的 GET 簽名 url,從而使瀏覽器的緩存控制無法進行。
我搜索了 web 但沒有成功,因為瀏覽器似乎使用完整的 url 作為緩存鍵,所以我真的很好奇在給定的情況下(nodejs,knox 庫)如何解決問題並使用緩存控制,同時仍然能夠為每個請求生成簽名 url,因為我需要驗證用戶的訪問權限。
我不敢相信沒有解決方案。
我正在使用 Java AmazonS3 客戶端,但過程應該是相同的。
有一種策略可用於處理這種情況。
您可以使用固定日期時間作為到期日期。 我把這個日期定為明天中午 12 點。
現在,每次生成 url 時,它在當天的 00:00 之前都是相同的。 這樣可以在某種程度上使用瀏覽器緩存。
如果您將 CloudFront 與 S3 一起使用,您可以使用自定義策略,如果您將每個 url 限制為用戶的 IP 和合理長的超時,這意味着當他們再次請求相同的內容時,他們將獲得相同的 URL,因此他們的瀏覽器可以緩存內容,但 URL 不適用於其他人(在不同的 IP 上)。
(參見: http : //docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html )
擴展@semir-deljić 答案。
每次我們調用getSignedUrl
函數時,它都會生成新的 URL。 即使存在Cache Control
標頭,這也會導致圖像不被緩存。
因此,我們使用計時庫來凍結時間。 現在當函數被調用時,它認為時間還沒有過去,它返回相同的 URL。
const moment = require('moment');
const tk = require("timekeeper");
function url4download(awsPath, awsKey) {
function getFrozenDate() {
return moment().startOf('week').toDate();
}
// Paramters for getSignedUrl function
const params = {
// Ref: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html
// Ref: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
Bucket: awsBucket,
Key: `${awsPath}/${awsKey}`,
// 604800 == 7 days
ResponseCacheControl: `public, max-age=604800, immutable`,
Expires: 604800, // 7 days is max
};
const url = tk.withFreeze(getFrozenDate(), () => {
return S3.getSignedUrl('getObject', params);
});
return url;
}
注意:使用moment().toDate()
,因為計時器需要一個本地日期對象。
即使是使用knox
庫的問題,我的回答也使用 aws 官方庫。
// This is how the AWS & S3 is initiliased.
const AWS = require('aws-sdk');
const S3 = new AWS.S3({
accessKeyId: awsAccessId,
secretAccessKey: awsSecretKey,
region: 'ap-south-1',
apiVersion: '2006-03-01',
signatureVersion: 'v4',
});
在計算已簽名的 URL 時,您可以將 'signingDate' 設置為過去的固定時刻,例如昨天早上,然后從該時刻開始計算到期時間。 不要忘記使用 UTC 並考慮時區。
import { S3Client, GetObjectCommand, GetObjectCommandInput } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
let signingDate = new Date();
signingDate.setUTCHours(0, 0, 0, 0);
signingDate.setUTCDate(signingDate.getUTCDate() - 1);
let params: GetObjectCommandInput = {
Bucket: BUCKET_NAME,
Key: filename
};
const command = new GetObjectCommand(params);
const url = await getSignedUrl(s3Client,
command, {
expiresIn: 3 * 3600 * 24, // 1 day until today + 1 expiration + 1 days for timezones
signableHeaders: new Set < string > (),
signingDate: signingDate
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.