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

Flask与JavaScript实现Blob音频文件提交问题求助

嗨,我来帮你理清楚问题出在哪,以及怎么解决~

问题根源拆解

你现在遇到的Bad Request错误,主要是两个核心问题导致的:

  • 原表单提交无效:你的表单里只有一个提交按钮,完全没有把录制好的Blob音频数据添加到表单中,点击submit时服务器根本没收到任何音频文件。
  • Ajax请求格式错误:你直接把blob作为请求数据发送,但没有用FormData对象包装——这是浏览器上传文件的标准格式,不符合规范的话,Flask的request.files就识别不到你的音频数据,自然报Bad Request。

修正后的完整实现

下面是调整后的前后端代码,一步步帮你解决问题:

1. 前端代码(录音+提交逻辑)

我们会把录制好的Blob存起来,点击提交时用FormData包装后发送,同时加入错误提示和麦克风资源释放:

<form>
  <div class="audio" id="audio"></div>
  <button type="button" id="submitBtn">提交录音</button>
</form>

<script type="text/javascript">
// 全局变量保存录制好的音频Blob
let recordedBlob = null;

// 请求麦克风权限并开始录制
navigator.mediaDevices.getUserMedia({audio: true})
.then(stream => {
  const recorder = new MediaRecorder(stream);
  const audioChunks = [];

  recorder.ondataavailable = e => {
    audioChunks.push(e.data);
    if (recorder.state === 'inactive') {
      // 生成完整的音频Blob
      recordedBlob = new Blob(audioChunks, {type: 'audio/webm'});
      // 创建预览音频元素
      const audioContainer = document.getElementById('audio');
      const previewAudio = document.createElement('audio');
      previewAudio.controls = true;
      previewAudio.src = URL.createObjectURL(recordedBlob);
      audioContainer.appendChild(previewAudio);
    }
  };

  recorder.start(100);
  // 5秒后自动停止录制,并释放麦克风资源
  setTimeout(() => {
    recorder.stop();
    stream.getTracks().forEach(track => track.stop());
  }, 5000);
})
.catch(err => {
  console.error('获取麦克风权限失败:', err);
  alert('请允许浏览器访问麦克风才能录制音频');
});

// 提交按钮点击事件
document.getElementById('submitBtn').addEventListener('click', () => {
  if (!recordedBlob) {
    alert('还没有录制音频哦,请等待录制完成');
    return;
  }

  // 用FormData包装音频文件,这是上传文件的标准方式
  const formData = new FormData();
  // 第一个参数是字段名,要和后端的字段名对应,这里叫'recorded_audio'
  formData.append('recorded_audio', recordedBlob, 'my_recording.webm');

  // 用fetch发送请求(也可以用jQuery的$.ajax,逻辑一致)
  fetch('/send', {
    method: 'POST',
    body: formData
  })
  .then(response => response.json())
  .then(result => {
    console.log('服务器响应:', result);
    alert('录音提交成功!');
  })
  .catch(err => {
    console.error('提交失败:', err);
    alert('提交出错了,请检查网络或重试');
  });
});
</script>

2. Flask后端代码

后端要对应前端的字段名来获取文件,同时做一些健壮性处理:

from flask import Flask, request, jsonify
import os

app = Flask(__name__)

# 确保保存录音的目录存在
os.makedirs('recordings', exist_ok=True)

@app.route('/send', methods=['POST'])
def submit_audio():
    if request.method == 'POST':
        # 这里的'recorded_audio'要和前端formData.append的第一个参数完全一致
        audio_file = request.files.get('recorded_audio')
        
        if not audio_file:
            return jsonify({'error': '未收到音频文件'}), 400
        
        # 打印调试信息,确认收到文件
        app.logger.debug(f'收到文件:{audio_file.filename},类型:{audio_file.content_type}')
        
        # 保存音频文件到服务器(根据你的需求选择是否保存)
        audio_file.save(os.path.join('recordings', audio_file.filename))
        
        return jsonify({'message': '音频提交成功'}), 200

if __name__ == '__main__':
    app.run(debug=True)

关键知识点补充

  • FormData的作用:它是浏览器专门用来构建multipart/form-data格式请求的对象,只有用它包装文件,后端才能通过request.files获取到上传的文件。
  • 字段名一致性:前端formData.append('xxx', blob)里的xxx,必须和后端request.files.get('xxx')里的xxx完全一致,否则后端找不到对应的文件。
  • 麦克风资源释放:录制停止后记得调用stream.getTracks().forEach(track => track.stop()),否则浏览器会一直占用麦克风,导致下次录制可能出问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:32:04