Vercel部署Next.js API调用AWS S3 SDK上传报ERR_HTTP_HEADERS_SENT错误
Next.js API在Vercel部署后调用@aws-sdk/client-s3报ERR_HTTP_HEADERS_SENT错误的解决思路
问题场景
本地环境下,Next.js API端点使用@aws-sdk/client-s3包可正常上传文件至S3,但部署到Vercel后,SDK抛出ERR_HTTP_HEADERS_SENT错误。此前该功能曾正常工作,且S3桶中仍保留当时成功上传的文件。
代码示例
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; import type { NextApiRequest, NextApiResponse } from "next"; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const s3Client = new S3Client({}); const uploadCommand = new PutObjectCommand({ Bucket: process.env.MY_S3_BUCKET, Key: "test/testUpload.json", Body: JSON.stringify({ message: "Hello World" }), }); const response = await s3Client.send(uploadCommand); res.status(200).json(response); }
错误信息
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client at new NodeError (node:internal/errors:399:5) at ClientRequest.setHeader (node:_http_outgoing:663:11) at mod.request (/var/task/___vc/__launcher.js:90:17) at /var/task/node_modules/@aws-sdk/node-http-handler/dist-cjs/node-http-handler.js:70:25 at new Promise (<anonymous>) at NodeHttpHandler.handle (/var/task/node_modules/@aws-sdk/node-http-handler/dist-cjs/node-http-handler.js:49:16) at async /var/task/node_modules/@aws-sdk/middleware-serde/dist-cjs/deserializerMiddleware.js:5:26 { code: 'ERR_HTTP_HEADERS_SENT', '$metadata': { attempts: 1, totalRetryDelay: 0 } }
使用的包版本
"@aws-sdk/client-s3": "3.278.0",
可能原因
该错误本质是HTTP响应已发送给客户端后,代码仍尝试修改响应头。在Vercel无服务器环境下,主要触发原因包括:
- AWS SDK默认的
NodeHttpHandler与Vercel的请求处理运行时存在冲突,Vercel的运行时可能提前终止请求上下文,导致SDK后续的头信息操作失效。 - 旧版本
@aws-sdk/client-s3存在与Vercel Node.js环境兼容的bug,后续版本已修复相关问题。 - 未捕获的异常导致代码路径重复发送响应。
解决方案
1. 替换HTTP Handler为FetchHttpHandler
使用AWS SDK提供的FetchHttpHandler替代默认的NodeHttpHandler,适配Vercel环境对Fetch API的良好支持,避免Node原生HTTP模块的冲突。
修改后的代码:
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; import { FetchHttpHandler } from "@aws-sdk/fetch-http-handler"; import type { NextApiRequest, NextApiResponse } from "next"; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { const s3Client = new S3Client({ requestHandler: new FetchHttpHandler(), }); const uploadCommand = new PutObjectCommand({ Bucket: process.env.MY_S3_BUCKET, Key: "test/testUpload.json", Body: JSON.stringify({ message: "Hello World" }), }); const response = await s3Client.send(uploadCommand); res.status(200).json(response); } catch (error) { res.status(500).json({ error: (error as Error).message }); } }
2. 升级@aws-sdk/client-s3到最新稳定版
旧版本(如3.278.0)存在已知的环境兼容问题,升级至最新稳定版可修复HTTP handler相关的bug:
npm install @aws-sdk/client-s3@latest
3. 确保请求上下文的单一响应
用try/catch包裹所有异步操作,确保无论成功或失败,仅发送一次HTTP响应,避免未捕获异常导致Vercel运行时额外触发响应操作。
4. 对齐Vercel与本地的Node.js版本
检查Vercel项目设置中的Node.js版本,确保与本地开发环境一致(例如均使用Node 18),避免版本差异导致的SDK行为不一致。
内容的提问来源于stack exchange,提问作者Brandon
相关产品推荐
相关产品推荐

