S3,签名URL和缓存

时间:2013-10-25 07:10:14

标签: node.js amazon-web-services amazon-s3 knox-amazon-s3-client

我正在使用knox nodejs-library在我的webapp(nodejs)上生成签名的URL。 然而问题出现了,对于每个请求,我需要为当前用户重新生成一个唯一的GET签名URL,使浏览器的缓存控制不在游戏中。

我搜索网络没有成功,因为浏览器似乎使用完整的网址作为缓存密钥所以我真的很好奇我怎么能在给定的情况下(nodejs,knox库)解决问题并使用缓存控制仍然能够为每个请求生成签名的URL,因为我需要验证用户的访问权限。

我无法相信没有解决方案。

3 个答案:

答案 0 :(得分:1)

扩展@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',
});

灵感:https://advancedweb.hu/cacheable-s3-signed-urls/

答案 1 :(得分:0)

如果您将CloudFront与S3一起使用,则可以使用自定义策略,如果您将每个网址限制为用户的IP以及相当长的超时,则意味着当他们再次请求相同的内容时,他们将获得相同的URL和因此,他们的浏览器可以缓存内容,但URL不适用于其他人(在不同的IP上)。

(见:http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html

答案 2 :(得分:0)

我正在使用Java AmazonS3客户端,但是过程应该相同。

有一种可以用来处理这种情况的策略。

您可以使用固定的日期时间作为到期日期。我将此日期设置为明天下午12点

现在,每次您生成一个URL时,在当天直到00:00都是一样的。这样,浏览器缓存就可以得到一定程度的利用。