求助:使用AWS Lambda+API Gateway上传S3的文件无法预览
问题描述
我通过AWS Lambda搭配API Gateway将图片、视频上传至S3 Bucket,上传流程显示成功且能在响应中获取到文件的Location链接,但点击链接无法预览图片,报错提示“图像无法显示,包含错误”。需要实现支持图片、音频及视频的正常上传与预览功能。
相关Lambda代码
const multipart = require('aws-lambda-multipart-parser'); const AWS = require('aws-sdk'); const { config } = require('./config') const { v4: uuidv4 } = require('uuid') const fs = require('fs'); const s3 = new AWS.S3({ accessKeyId:config?.dev?.aws_s3?.ACCESS_KEY, secretAccessKey:config?.dev?.aws_s3?.SECRET_KEY }) // 从事件中解析数据(event作为参数传入) const result = await multipart.parse(param); let myFile= result.media.filename.split(".") let fileType = myFile[myFile.length - 1]; const fileName = uuidv4()+'.'+fileType; const uploadData = { Bucket : config?.dev?.aws_s3?.BUCKETNAME, Key : fileName, Body : Buffer.from(result.media.content, 'binary'), ContentType : result.media.contentType, ACL : 'public-read', Conditions: [ ['content-length-range', 0, 10000000] // 10 Mb ] } try { const responseData = await s3.upload(uploadData).promise() return { "body" : { "message" : "Image uploaded successfully", "data" : responseData }, 'statusCode': 200 } } catch (e) { return { "body" : { "message" : e.message }, 'statusCode': 500 } }
上传请求截图

响应结果
{ "message": "Image uploaded successfully", "data": { "ETag": "\"662d32878c3e0628d2958e95fc055855\"", "Location": "https://bucketname.s3.amazonaws.com/03c2fcd1-ab92-42a8-93cf-d6a89545c77e.jpeg", "key": "03c2fcd1-ab92-42a8-93cf-d6a89545c77e.jpeg", "Key": "03c2fcd1-ab92-42a8-93cf-d6a89545c77e.jpeg", "Bucket": "bucketname" } }
解决方案
核心问题定位
代码中Buffer.from(result.media.content, 'binary')是导致文件损坏的直接原因:aws-lambda-multipart-parser解析后的文件内容本身已经是Buffer类型,强行用binary编码二次转换会破坏原始二进制数据,上传到S3的文件自然无法正常预览/播放。
另外,Conditions是生成预签名URL时的配置参数,s3.upload()方法并不需要该字段,应移除避免无效参数干扰。
修正后的代码
const multipart = require('aws-lambda-multipart-parser'); const AWS = require('aws-sdk'); const { config } = require('./config') const { v4: uuidv4 } = require('uuid') const s3 = new AWS.S3({ accessKeyId:config?.dev?.aws_s3?.ACCESS_KEY, secretAccessKey:config?.dev?.aws_s3?.SECRET_KEY }) // 从事件中解析数据(event作为参数传入) const result = await multipart.parse(param); const myFile = result.media.filename.split(".") const fileType = myFile[myFile.length - 1]; const fileName = uuidv4()+'.'+fileType; // 文件大小校验(10MB) const MAX_SIZE = 10 * 1024 * 1024; if (result.media.content.length > MAX_SIZE) { return { body: { message: "文件大小不能超过10MB" }, statusCode: 400 }; } // 文件类型校验(仅允许图片、音频、视频) const allowedTypes = ['image/', 'audio/', 'video/']; const isAllowed = allowedTypes.some(type => result.media.contentType.startsWith(type)); if (!isAllowed) { return { body: { message: "仅支持图片、音频、视频类型文件上传" }, statusCode: 400 }; } const uploadData = { Bucket : config?.dev?.aws_s3?.BUCKETNAME, Key : fileName, Body : result.media.content, // 直接使用解析后的Buffer内容 ContentType : result.media.contentType, ACL : 'public-read' } try { const responseData = await s3.upload(uploadData).promise() return { body : { message : "文件上传成功", data : responseData }, statusCode: 200 } } catch (e) { return { body : { message : `上传失败:${e.message}` }, statusCode: 500 } }
额外优化说明
- 文件类型校验:新增对
contentType的校验,仅允许image/*、audio/*、video/*类型文件上传,避免非法文件流入。 - 文件大小校验:通过代码直接判断文件字节长度,替代无效的
Conditions参数,确保大小限制生效。 - 错误信息优化:在捕获异常时补充错误前缀,让返回信息更直观。
验证方式
重新部署修正后的Lambda函数,上传图片、音频或视频文件:
- 访问响应中的Location链接,确认图片可预览、音频/视频可正常播放;
- 下载文件到本地,验证文件能正常打开,无损坏情况。
内容的提问来源于stack exchange,提问作者Vincent
相关产品推荐
相关产品推荐

