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

Google Cloud Function调用AWS S3 getObject请求超时无响应

问题描述

在Google Cloud Function(以下简称GCF)中调用AWS SDK的S3接口时,无论使用SDK v2的s3.getObject方法还是SDK v3的.send方法,请求都会持续超时无返回。本地开发阶段使用Node/Express服务测试同一段逻辑运行完全正常,本地可正常运行的代码片段如下:

通用请求参数定义:

const params = {
  Bucket: process.env.AWS_BUCKET_NAME,
  Key: key,
};
  • SDK v3版本调用实现:
const createParams = new GetObjectCommand(params);
const response = await client.send(createParams);
  • SDK v2版本调用实现:
const s3Asset = await s3.getObject(params).promise();

两种实现本地都可以正常拉取目标文件:单文件场景直接返回Buffer格式,多文件场景打包为Zip后返回。

代码部署到GCF后,S3请求始终无响应最终触发函数超时。已完成的排查验证项:

  • 函数内发起请求访问google.com可正常返回200状态码,确认公网访问能力正常
  • 已配置VPC连接器允许所有流量出站
  • 相关环境变量(AWS密钥、桶名、区域等)均已正确配置

部署使用的GCF完整代码如下:

const s3 = new S3Client({
  credentials: {
    secretAccessKey: process.env.AWS_ACCESS_KEY,
    accessKeyId: process.env.AWS_ACCESS_ID,
  },
  region: process.env.AWS_REGION,
  correctClockSkew: true,
});

exports.downloadAssets = async (req, res) => {
  res.set('Access-Control-Allow-Origin', '*');
  if (req.method === 'OPTIONS') {
    console.log('Hit OPTIONS');
    res.set('Access-Control-Allow-Methods', 'POST');
    res.set('Access-Control-Allow-Headers', 'Content-Type');
    res.set('Access-Control-Max-Age', '3600');
    res.status(204).send('');
  } else {
    console.log('***** Assets to download\n', req.body?.assets, '*****');
    try {
      if (req.body?.assets) {
        var params = {
          Bucket: process.env.AWS_BUCKET_NAME,
          Key: key,
        };
        const s3Asset = await s3.getObject(params).promise(); // 执行到此处卡住
        console.log('*** I have asset *** \n',s3Asset) // 该日志永远不会打印
        res.send({ buffer: s3Asset.Body, name: 'nameOfFile', mimeType: s3Asset.ContentType });
      } else {
        return res.status(400).json({ error: 'No Assets Sent' });
      }
    } catch (e) {
      console.log('Error downloading assets: \n', e);
      res.status(400).json({ error: e.message });
    }
  }
};
问题原因与修复方案

按以下优先级逐一排查修复:

1. 修正AWS SDK版本混用问题

你部署代码中初始化的是SDK v3版本的S3Client,该类不存在实例方法getObject()——v3版本的所有S3操作都需要通过send()方法传入对应Command执行。本地能跑通通常是因为本地开发环境同时安装了v2版本的aws-sdk依赖,初始化的是v2版S3实例;部署到GCF时依赖安装逻辑和本地不一致,要么是v3实例调用不存在的方法导致Promise一直处于pending状态,要么是依赖版本冲突导致请求逻辑异常。

如果使用v3版本SDK,将S3调用逻辑改为v3标准写法:

// 顶部补充对应依赖导入
const { S3Client, GetObjectCommand } = require("@aws-sdk/client-s3");

// 调用部分替换原有v2风格代码
const command = new GetObjectCommand(params);
const s3Response = await s3.send(command);
// 注意v3返回的Body是ReadableStream类型,需要手动转换为Buffer
const fileBuffer = Buffer.from(await s3Response.Body.transformToByteArray());

如果使用v2版本SDK,将初始化逻辑替换为v2标准写法,不要混用v3的S3Client:

const AWS = require('aws-sdk');
const s3 = new AWS.S3({
  accessKeyId: process.env.AWS_ACCESS_ID,
  secretAccessKey: process.env.AWS_ACCESS_KEY,
  region: process.env.AWS_REGION,
  correctClockSkew: true,
});
// 原有s3.getObject(params).promise()的写法可以正常保留

2. 强制SDK使用IPv4协议栈

这是GCF调用AWS服务的高频已知问题:GCF的Node.js运行时默认优先解析域名的AAAA(IPv6)记录,但GCF默认网络、VPC连接器默认都不支持IPv6出站。你能正常访问google.com是因为该域名可自动回退到IPv4连接,而部分区域的S3端点会卡在IPv6连接握手阶段、不会自动回退,最终导致请求超时。

在SDK初始化时强制指定使用IPv4栈即可修复:

  • v3版本配置方式:
const http = require('http');
const https = require('https');
const { NodeHttpHandler } = require("@aws-sdk/node-http-handler");

const s3 = new S3Client({
  // 原有credentials、region等配置保留
  requestHandler: new NodeHttpHandler({
    httpAgent: new http.Agent({ family: 4 }),
    httpsAgent: new https.Agent({ family: 4 }),
    connectionTimeout: 10000,
    socketTimeout: 10000
  })
});
  • v2版本配置方式:
const https = require('https');
const s3 = new AWS.S3({
  // 原有配置保留
  httpOptions: {
    agent: new https.Agent({ family: 4 }),
    timeout: 10000
  },
  maxRetries: 3
});

3. 补全代码中未定义的key变量

当前部署代码里params的Key字段直接使用了未定义的key变量,正常逻辑应该从req.body.assets中提取待下载的文件Key,未定义变量虽然会直接抛出ReferenceError,但如果上层有吞错逻辑也可能表现为请求卡住,需要补全这部分业务逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 14:36:24