AWS异步调用签名过期问题求助(Fedora/Heroku+Node.js Express)
先看你报错的核心信息:
Signature expired: 20171114T190104Z is now earlier than 20180323T213705Z (20180323T214205Z - 5 min.)
再看你的代码,最致命的问题是请求头里的日期和Credential中的日期都是硬编码的2017年的旧值——这和时钟同步、密钥过期无关,哪怕你的系统时钟完全准确,用两年前的日期请求AWS,必然触发签名过期。
一、修复硬编码的请求日期
AWS签名要求X-Amz-Date必须是请求发送时的UTC时间(误差不能超过5分钟),同时Credential里的日期部分(key/20171114/us-west-1/awis/aws4_request中的20171114)必须是当天的日期格式(YYYYMMDD)。你需要动态生成这些值,而不是写死:
修改后的代码示例
function(callback) { // third call var results = ''; // 生成符合AWS要求的当前UTC时间 const currentDate = new Date(); const amzDate = currentDate.toISOString().replace(/[:-]/g, '').split('.')[0] + 'Z'; const dateStamp = amzDate.slice(0, 8); // 提取YYYYMMDD格式的日期 var options = { host: urlObject.host, protocol: urlObject.protocol, path: urlObject.path, headers: { // 更新Credential中的日期为当天 Authorization: `AWS4-HMAC-SHA256 Credential=key/${dateStamp}/us-west-1/awis/aws4_request, SignedHeaders=host;x-amz-date, Signature=key`, 'Content-Type': 'application/xml', 'X-Amz-Date': amzDate, // 使用动态生成的当前时间 Accept: 'application/xml', }, }; https.get(options, resource => { resource.setEncoding('utf8'); resource.on('data', function(data) { results += data; }); resource.on('end', function() { callback(null, results); }); resource.on('error', function(err) { callback(err); }); }); }
另外,强烈建议使用AWS SDK for JavaScript而非手动构造HTTP请求和签名——SDK会自动处理日期、签名生成、密钥管理等细节,完全避免这类低级错误。比如调用AWIS服务时,SDK能帮你搞定所有签名逻辑,不用自己拼Authorization头。
二、关于时钟同步的补充
你提到已经设置了自动同步,手动调整时钟也没用,这很正常——因为问题根源是硬编码的旧日期,和系统时钟无关。不过还是可以顺便确认下系统时间是否和NTP服务器同步(Fedora下执行timedatectl status查看状态),但这不是当前问题的解决方案。
三、关于AWS密钥过期的疑问
AWS的访问密钥(Access Key ID和Secret Access Key)默认不会自动过期,除非你在IAM控制台手动设置了过期时间,或者密钥被禁用/删除。
如果怀疑密钥有问题,可以按以下步骤排查:
- 登录AWS控制台,进入IAM -> 用户,找到你的IAM用户
- 切换到安全凭证标签,查看访问密钥的状态:
- 如果状态是已禁用,点击启用即可
- 如果设置了过期时间且已过期,需要点击创建访问密钥生成新的密钥,然后替换代码中的
key部分 - 如果密钥已被删除,同样需要生成新的访问密钥
内容的提问来源于stack exchange,提问作者Alex Ironside

