如何修改Javascript代码安全上传Blob至AWS S3避免文件损坏
解决Blob上传S3后文件损坏的问题
你的核心问题是二进制音频数据在传输过程中被错误编码,导致S3存储的文件无法正常播放。下面给你几个可行的JS修改方案,配合Lambda的调整就能彻底解决这个问题:
方案1:用FormData封装Blob(推荐,贴合标准文件上传流程)
直接传递Blob时,jQuery对二进制数据的处理容易出现编码偏差,用FormData可以确保数据以正确的multipart格式传输:
修改JS中ondataavailable里的AJAX逻辑:
// 提前声明变量,避免全局污染 var audioChunks = []; var rec; navigator.mediaDevices.getUserMedia({audio:true}) .then(stream => { // 可以指定录制格式,比如webm(Chrome默认)或mp4(Safari支持) rec = new MediaRecorder(stream, { mimeType: 'audio/webm' }); rec.ondataavailable = e => { audioChunks.push(e.data); if (rec.state == "inactive"){ const blob = new Blob(audioChunks, { type: 'audio/webm' }); const formData = new FormData(); // 第三个参数是文件名,格式要和Blob的type一致 formData.append('audio-file', blob, 'recording.webm'); $.ajax({ type: "POST", url: 'https://aws-api-url/prod/audio', data: formData, crossDomain: true, processData: false, // 阻止jQuery自动处理FormData contentType: false, // 让浏览器自动生成multipart的Content-Type headers: {"x-api-key": 'someKey'}, success: () => console.log('音频上传成功'), error: (err) => console.error('上传失败:', err) }); } } }) .catch(e=>console.log(e));
对应的Lambda需要解析multipart数据(可以用aws-lambda-multipart-parser第三方库):
import json import boto3 from lambda_multipart_parser import parser def lambda_handler(event, context): # 强烈建议用IAM角色授权S3权限,不要硬编码密钥! s3_client = boto3.client('s3') parsed_data = parser.parse(event) audio_file = parsed_data['audio-file'] # 上传时指定正确的Content-Type,确保下载后能正常播放 s3_client.put_object( Body=audio_file.content, Bucket='bucket', Key='incoming/recording.webm', ContentType=audio_file.content_type ) return { 'statusCode': 200, 'headers': { 'Access-Control-Allow-Origin': '*' }, 'body': json.dumps('音频上传成功') }
方案2:将Blob转为Base64字符串传输(更简单,无需处理multipart)
把二进制数据转成Base64字符串,以JSON格式传输,Lambda解码后再保存原始二进制:
修改JS代码:
var audioChunks = []; var rec; navigator.mediaDevices.getUserMedia({audio:true}) .then(stream => { rec = new MediaRecorder(stream, { mimeType: 'audio/webm' }); rec.ondataavailable = e => { audioChunks.push(e.data); if (rec.state == "inactive"){ const blob = new Blob(audioChunks, { type: 'audio/webm' }); const reader = new FileReader(); reader.onload = function(event) { // 去掉Base64前缀(data:audio/webm;base64,),只保留编码内容 const base64Audio = event.target.result.split(',')[1]; $.ajax({ type: "POST", url: 'https://aws-api-url/prod/audio', data: JSON.stringify({ audio: base64Audio }), crossDomain: true, processData: false, headers: {"x-api-key": 'someKey'}, contentType: 'application/json', // 明确告知后端是JSON格式 success: () => console.log('音频上传成功'), error: (err) => console.error('上传失败:', err) }); }; reader.readAsDataURL(blob); } } }) .catch(e=>console.log(e));
对应的Lambda修改:
import json import boto3 import base64 def lambda_handler(event, context): s3_client = boto3.client('s3') request_body = json.loads(event['body']) # 解码Base64字符串为原始二进制数据 audio_binary = base64.b64decode(request_body['audio']) s3_client.put_object( Body=audio_binary, Bucket='bucket', Key='incoming/recording.webm', ContentType='audio/webm' ) return { 'statusCode': 200, 'headers': { 'Access-Control-Allow-Origin': '*' }, 'body': json.dumps('音频上传成功') }
额外重要提醒
- 禁止硬编码AWS密钥:给Lambda配置具备S3上传权限的IAM角色,删除代码中硬编码的
aws_access_key_id和aws_secret_access_key,这是严重的安全漏洞。 - 匹配音频格式:不同浏览器的MediaRecorder默认格式不同(Chrome为webm,Safari为mp4),创建Blob时要指定正确的
type,同时S3上传时设置对应的ContentType,否则下载后的文件可能无法播放。 - 变量提前声明:在JS开头显式声明
audioChunks和rec变量,避免全局变量污染引发的潜在问题。
内容的提问来源于stack exchange,提问作者Jaskaran Singh Puri
相关产品推荐
相关产品推荐

