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

使用AWS Node.js SDK的s3.upload在Vercel环境间歇性出现NetworkError

问题分析与解决方案

问题核心

在Vercel API路由中使用AWS Node.js SDK的s3.upload接口上传图片时,间歇性触发NetworkError,错误本质为ERR_HTTP_HEADERS_SENT(向客户端发送响应后无法再设置请求头)。相同代码在CLI或其他Lambda环境中运行正常,CORS已排查排除影响,怀疑与Vercel环境特性或AWS SDK版本有关。

错误详情

{
  "data": {
    "errorMessage": "NetworkingError [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client",
    "errorType": "Runtime.UnhandledPromiseRejection",
    "reason": {
      "code": "NetworkingError",
      "errorMessage": "Cannot set headers after they are sent to the client",
      "errorType": "NetworkingError",
      "hostname": "bucket.s3.amazonaws.com",
      "message": "Cannot set headers after they are sent to the client",
      "region": "us-east-1",
      "retryable": true,
      "stack": [
        "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client",
        "    at new NodeError (internal/errors.js:322:7)",
        "    at ClientRequest.setHeader (_http_outgoing.js:561:11)",
        "    at Object.mod.request (/var/task/___vc/__launcher.js:90:17)",
        "    at features.constructor.handleRequest (/var/task/node_modules/aws-sdk/lib/http/node.js:45:23)",
        "    at executeSend (/var/task/node_modules/aws-sdk/lib/event_listeners.js:452:29)",
        "    at Request.SEND (/var/task/node_modules/aws-sdk/lib/event_listeners.js:466:9)",
        "    at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:102:18)",
        "    at Request.emit (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:78:10)",
        "    at Request.emit (/var/task/node_modules/aws-sdk/lib/request.js:686:14)",
        "    at Request.transition (/var/task/node_modules/aws-sdk/lib/request.js:22:10)"
      ],
      "time": "2023-04-27T11:03:16.773Z"
    },
    "stack": [
      "Runtime.UnhandledPromiseRejection: NetworkingError [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client",
      "    at process.<anonymous> (/var/runtime/index.js:35:15)",
      "    at process.emit (events.js:412:35)",
      "    at process.emit (domain.js:475:12)",
      "    at processPromiseRejections (internal/process/promises.js:245:33)",
      "    at processTicksAndRejections (internal/process/task_queues.js:96:32)"
    ]
  }
}

问题根源

从错误栈可见,问题出在Vercel的___vc/__launcher.js中尝试设置请求头时,发现响应已发送。主要原因包括:

  1. API路由提前终止响应:代码可能在s3.upload完成前就调用了res.send()/res.json(),导致Vercel结束请求上下文,而AWS SDK后续的重试或回调操作仍试图修改请求头。
  2. AWS SDK v2回调/重试机制与Vercel环境不兼容:V2的回调模式可能在Vercel函数运行时中出现Promise未捕获,或重试时上下文已被销毁。
  3. Vercel函数超时:若上传耗时接近Vercel默认超时(10秒),函数被提前终止后,SDK后续操作会触发错误。

解决方案

  • 确保响应仅在上传完成后发送:改用async/await替代回调,等待s3.upload的Promise完成后再返回响应:
    import AWS from 'aws-sdk';
    const s3 = new AWS.S3();
    
    export default async function handler(req, res) {
      try {
        const uploadResult = await s3.upload({
          Bucket: 'your-bucket',
          Key: 'file-key',
          Body: req.body
        }).promise();
        res.status(200).json({ success: true, data: uploadResult });
      } catch (err) {
        res.status(500).json({ success: false, error: err.message });
      }
    }
    
  • 升级到AWS SDK v3:V3采用模块化设计,兼容性更好,可避免V2中部分回调与Serverless环境的冲突:
    import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
    const s3Client = new S3Client({ region: 'us-east-1' });
    
    export default async function handler(req, res) {
      try {
        const command = new PutObjectCommand({
          Bucket: 'your-bucket',
          Key: 'file-key',
          Body: req.body
        });
        const uploadResult = await s3Client.send(command);
        res.status(200).json({ success: true, data: uploadResult });
      } catch (err) {
        res.status(500).json({ success: false, error: err.message });
      }
    }
    
  • 调整AWS SDK重试配置:若重试是触发问题的原因,可禁用重试或调整重试次数,避免响应发送后仍有后续操作:
    const s3 = new AWS.S3({
      maxRetries: 0,
      retryDelayOptions: { base: 0 }
    });
    
  • 延长Vercel函数超时:在vercel.json中设置更长的超时时间,确保上传操作能完成:
    {
      "functions": {
        "api/**/*.js": {
          "timeout": 30
        }
      }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 15:07:50