NodeJS S3,签名URL和缓存

bttbmeg0  于 2023-08-04  发布在  Node.js
关注(0)|答案(5)|浏览(120)

我正在使用knox nodejs-library在我的webapp(nodejs)上生成签名的url。然而问题出现了,对于每个请求,我需要为当前用户重新生成一个唯一的GET签名URL,这使得浏览器的缓存控制无法进行。
我在网上搜索过,但没有成功,因为浏览器似乎使用完整的url作为缓存键,所以我真的很好奇,在给定的情况下(nodejs,knox库),我如何解决这个问题,并使用缓存控制,同时仍然能够为每个请求生成签名的url,因为我需要验证用户的访问权限。
我不敢相信没有解决办法。

busg9geu

busg9geu1#

我正在使用Java AmazonS3客户端,但过程应该是一样的。
有一种策略可以用来处理这种情况。
您可以使用固定的日期时间作为到期日期。我把这个日期设定为明天下午12点
现在,每次您生成一个URL,它将在一天中保持不变,直到00:00。这样,浏览器缓存可以在某种程度上使用。

wa7juj8i

wa7juj8i2#

扩展@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()作为计时器需要一个Native Date Object。

更坚韧的问题是使用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/

pengsaosao

pengsaosao3#

如果您将CloudFront与S3一起使用,则可以使用自定义策略,如果您将每个URL限制为用户的IP和合理的长超时,则意味着当他们再次请求相同的内容时,他们将获得相同的URL,因此他们的浏览器可以缓存内容,但URL将不适用于其他人(在不同的IP上)。
(see:http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html

ghhkc1vu

ghhkc1vu4#

当计算签名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
    });

字符串

qacovj5a

qacovj5a5#

您可以使用window.caches创建自己的浏览器缓存逻辑
参见this other stackoverflow question中的示例

相关问题