You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

S3预签名URL下载图片无法打开,macOS报错求助

S3预签名URL下载文件在macOS报错问题

我使用以下代码通过S3存储图片文件,由于图片无法公开访问,因此使用预签名URL生成带过期时间的认证链接。所有流程看似正常,但点击生成的getUrl下载文件后,macOS弹出错误提示:无法下载此文件。无法从s3.amazonaws.com下载。

const {
  S3Client,
  PutObjectCommand,
  DeleteObjectCommand,
  DeleteObjectsCommand,
  GetObjectCommand,
} = require('@aws-sdk/client-s3');
const awsPresigner = require('@aws-sdk/s3-request-presigner');

const getCommand = (fileNames, action) => {
  let ObjectCommand;
  const params = {
    Bucket: process.env.STORAGE_EVENT_S3_BUCKET,
    Key: fileNames,
  };
  switch (action) {
    case 'put': {
      ObjectCommand = PutObjectCommand;
      break;
    }

    case 'delete': {
      ObjectCommand = DeleteObjectCommand;
      break;
    }

    case 'deleteMany': {
      ObjectCommand = DeleteObjectsCommand;
      params.Delete = {
        Objects: params.Key.map((key) => ({ Key: key })),
      };
      delete params.Key;
      break;
    }

    default: {
      ObjectCommand = GetObjectCommand;
      break;
    }
  }

  const command = new ObjectCommand(params);

  return command;
};

const getPresignedUrl = (fileName, action) => {
  const command = getCommand(fileName, action);

  const s3Client = new S3Client({
    credentials: {
      accessKeyId: process.env.AWS_PUBLIC_KEY,
      secretAccessKey: process.env.AWS_PRIVATE_KEY,
    },
    region: process.env.AWS_REGION,
  });

  return awsPresigner.getSignedUrl(s3Client, command, {
    expiresIn: 60 * 60,
  });
};

const run = async () => {
  const putUrl = await getPresignedUrl('a/b.png', 'put');

  const getUrl = await getPresignedUrl('a/b.png', 'get');

  console.log(putUrl, '\n', getUrl)
}

run();

排查方向与解决方案

1. 检查IAM权限

确保生成预签名URL使用的AWS密钥对应的IAM用户,拥有目标S3对象的s3:GetObject权限。可通过IAM策略验证:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::你的Bucket名称/*"
    }
  ]
}

2. 校验预签名URL参数

  • 确认Bucket名称、文件Key(a/b.png)完全匹配S3中实际存储的对象路径,注意路径大小写敏感
  • 检查生成URL时指定的AWS区域是否与Bucket所在区域完全一致

3. 验证SDK版本兼容性

确保@aws-sdk/client-s3和@aws-sdk/s3-request-presigner版本完全一致,版本不匹配可能导致签名无效。执行命令查看并统一版本:

npm list @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
npm install @aws-sdk/client-s3@x.x.x @aws-sdk/s3-request-presigner@x.x.x

4. 测试URL有效性

先用终端命令测试预签名URL是否能正常获取内容,排除系统设置问题:

curl -v "你的预签名getUrl"

如果curl能返回文件内容,说明是macOS安全设置阻止了浏览器下载,可尝试:

  • 在「系统设置-隐私与安全性」中允许该下载
  • 换用其他浏览器测试

5. 优化代码复用S3客户端

每次生成URL都创建新的S3Client实例可能导致不必要的开销,建议将客户端实例化移到函数外部复用:

// 全局复用S3客户端
const s3Client = new S3Client({
  credentials: {
    accessKeyId: process.env.AWS_PUBLIC_KEY,
    secretAccessKey: process.env.AWS_PRIVATE_KEY,
  },
  region: process.env.AWS_REGION,
});

const getPresignedUrl = async (fileName, action) => {
  if (!fileName || !action) throw new Error('fileName和action为必填参数');
  
  const command = getCommand(fileName, action);
  return awsPresigner.getSignedUrl(s3Client, command, {
    expiresIn: 60 * 60,
  });
};

内容的提问来源于stack exchange,提问作者Chicky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 09:30:26