本地正常的S3上传Lambda部署后失效问题求助
问题诊断与解决方案
一、文件损坏/无法查看的修复方案
问题核心是Lambda处理API Gateway请求时,二进制数据编码/解码逻辑错误,导致上传到S3的文件并非原始二进制内容。
代码层面修复
调整Node.js代码,正确处理二进制请求体并保留文件元数据:
const AWS = require('aws-sdk'); const s3 = new AWS.S3(); exports.handler = async (event) => { // 根据API Gateway标记判断是否需要Base64解码 const fileContent = Buffer.from(event.body, event.isBase64Encoded ? 'base64' : 'utf8'); const uploadParams = { Bucket: 'your-target-bucket', Key: event.queryStringParameters?.fileName || 'default-file-name', Body: fileContent, // 保留原始请求的Content-Type,确保S3文件元数据正确 ContentType: event.headers['content-type'] || 'application/octet-stream' }; try { await s3.putObject(uploadParams).promise(); return { statusCode: 200, body: JSON.stringify({ success: true, message: '文件上传成功' }) }; } catch (err) { return { statusCode: 500, body: JSON.stringify({ success: false, error: err.message }) }; } };
API Gateway配置修复
- 开启二进制媒体类型:进入API Gateway控制台,找到对应API的「设置」页面,添加需要支持的二进制类型(如
image/*、application/pdf或通配符*/*)。 - 集成请求配置:将集成请求的「内容处理」设置为「通过(Passthrough)」,避免API Gateway自动修改二进制数据。
二、大文件上传报错的修复方案
问题根源是API Gateway默认最大请求 payload 为10MB,Lambda同步调用最大payload为6MB,超过限制会触发报错。
方案1:调整基础配置(支持最大10MB文件)
在Serverless框架配置文件中增加API Gateway的payload限制:
service: s3-upload-service provider: name: aws runtime: nodejs18.x apiGateway: maximumPayloadSize: 10485760 # 10MB,单位为字节 functions: uploadToS3: handler: handler.uploadToS3 events: - http: path: upload method: post cors: true request: contentHandling: CONVERT_TO_BINARY # 开启二进制转换支持
注意:此方案仅支持最大10MB的文件,超过10MB需用方案2。
方案2:预签名URL上传(推荐大文件场景)
绕过API Gateway和Lambda的payload限制,让前端直接通过S3预签名URL上传文件:
Lambda生成预签名URL的代码
const AWS = require('aws-sdk'); const s3 = new AWS.S3(); exports.getPresignedUrl = async (event) => { const { fileName, contentType } = JSON.parse(event.body); const params = { Bucket: 'your-target-bucket', Key: fileName, ContentType: contentType, Expires: 3600 // URL有效期1小时 }; try { const presignedUrl = s3.getSignedUrl('putObject', params); return { statusCode: 200, body: JSON.stringify({ presignedUrl }) }; } catch (err) { return { statusCode: 500, body: JSON.stringify({ error: err.message }) }; } };
Serverless配置新增函数
functions: getPresignedUrl: handler: handler.getPresignedUrl events: - http: path: get-presigned-url method: post cors: true
前端上传逻辑示例
async function uploadFile(file) { // 先请求预签名URL const urlResp = await fetch('/get-presigned-url', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ fileName: file.name, contentType: file.type }) }); const { presignedUrl } = await urlResp.json(); // 直接上传到S3 await fetch(presignedUrl, { method: 'PUT', body: file, headers: { 'Content-Type': file.type } }); }
三、额外检查项
- 确认Lambda的IAM角色拥有
s3:PutObject权限,且权限范围包含目标S3桶。 - 若使用预签名URL方案,需配置S3桶的CORS规则,允许前端PUT请求:
<CORSConfiguration> <CORSRule> <AllowedOrigin>*</AllowedOrigin> <AllowedMethod>PUT</AllowedMethod> <AllowedHeader>*</AllowedHeader> </CORSRule> </CORSConfiguration>
内容的提问来源于stack exchange,提问作者Arin Prajapati
相关产品推荐
相关产品推荐

