我正在我的Web应用程序(nodejs)上使用knox nodejs库生成已签名的URL。
然而,问题出现了,对于每个请求,我都需要重新生成当前用户的唯一GET签名URL,使浏览器的缓存控制失效。
我在网上搜索了很久,但没有成功,因为浏览器似乎将完整的URL作为缓存键值,所以我真的很好奇如何在给定情况下(nodejs,knox库)解决问题,并在仍然能够为每个请求生成签名URL的同时使用缓存控制,因为我需要验证用户的访问权限。
虽然我不相信没有解决方案。
我正在我的Web应用程序(nodejs)上使用knox nodejs库生成已签名的URL。
然而,问题出现了,对于每个请求,我都需要重新生成当前用户的唯一GET签名URL,使浏览器的缓存控制失效。
我在网上搜索了很久,但没有成功,因为浏览器似乎将完整的URL作为缓存键值,所以我真的很好奇如何在给定情况下(nodejs,knox库)解决问题,并在仍然能够为每个请求生成签名URL的同时使用缓存控制,因为我需要验证用户的访问权限。
虽然我不相信没有解决方案。
我正在使用Java AmazonS3客户端,但处理过程应相同。
有一种策略可以用来处理这种情况。
您可以使用固定的日期时间作为到期日期。 我将此日期设置为明天中午12点。
现在每次生成URL时,它将在当天内始终保持相同,直到00:00。 这样浏览器缓存就可以在一定程度上使用。
s3.getSignedUrl("getObject", {Bucket: "mybucket", Key:'myImage", Expires:18000} )
,它指定了URL在18000秒或5小时后过期。如何设置固定的日期时间而不是一个时间量作为过期时间? - KJ Ang扩展@semir-deljić的回答。
每次调用getSignedUrl
函数,它都会生成新的URL。这将导致即使存在Cache Control
头也无法缓存图片。
因此,我们使用timekeeper库来冻结时间。现在当函数被调用时,它认为时间没有流逝,并返回相同的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',
});
getSignedUrl
函数,使其认为它在过去的一个“预设”时间内。例如,每天10分钟间隔的预设时间是1pm、1:10pm、1:20pm等。实际例子:当用户在1:02pm请求图像时,服务器设置为最近的预设时间(使用timekeeper
),即1pm,并运行s3.getSignedUrl()
;这就好像服务器在1pm运行了s3.getSignedUrl()
;1.04pm的请求将在1pm运行s3.getSignedUrl()
,以此类推。因此,从1pm到1:10pm生成的所有URL都是相同的!我测试过了,它可行! - KJ Angtimekeeper
的作用更像是一个可以前往指定时间的时间旅行者。代码tk.withFreeze(time, callback)
将Date对象设置为指定时间,然后运行callback
。因此,timekeeper
的有用之处在于,你可以在任何时候,向后或向前前往指定的时间点并运行你的callback
。 - KJ Angimport { 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
});