17

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

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

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

4

4 回答 4

3

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

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

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

现在,每次生成一个 url 时,它会一直保持不变,直到 00:00。这样可以在某种程度上使用浏览器缓存。

于 2019-06-11T12:18:50.480 回答
2

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

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

于 2013-10-25T07:40:58.237 回答
2

扩展@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/

于 2021-01-26T11:04:34.917 回答
0

在计算签名 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
    });
于 2022-02-16T09:38:44.463 回答