S3、签名 URL 和缓存

问题描述 投票:0回答:5

我正在使用 knox nodejs-library 在我的 web 应用程序 (nodejs) 上生成签名 URL。 然而问题出现了,对于每个请求,我都需要为当前用户重新生成一个唯一的 GET 签名 URL,从而将浏览器的缓存控制排除在游戏之外。

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

我不敢相信没有解决方案。

node.js amazon-web-services amazon-s3 knox-amazon-s3-client
5个回答
4
投票

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

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

您可以使用固定日期时间作为到期日期。我把这个日期定为明天中午 12 点

现在,每次生成网址时,当天的网址都是相同的,直到 00:00。这样就可以在某种程度上使用浏览器缓存。


4
投票

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

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


2
投票

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

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


2
投票

您可以使用 window.caches

创建自己的浏览器缓存逻辑

请参阅 另一个 stackoverflow 问题

中的示例

1
投票

计算签名 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
    });
© www.soinside.com 2019 - 2024. All rights reserved.