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

Flask/Typescript前后端集成问题:POST请求无法触发

Flask/TypeScript前后端集成POST请求失败排查

我在做Flask/Typescript服务端与客户端集成开发时,遇到POST请求无法正常工作的问题:点击按钮后,程序本该完成录音并将录音文件发送至服务器,服务器处理后返回接收响应,但实际POST请求根本没发起。

Flask服务端代码(app.py)

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/api/receive-recording', methods=['GET', 'POST'])  # Allow both GET and POST
def receive_recording():
    if request.method == 'POST':
        try:
            audio_data = request.data
            # Process the audio_data as needed
            return jsonify(message='I got the recording')
        except Exception as e:
            return jsonify(error=str(e)), 400
    else:
        return jsonify(message='Hello! This is the audio recording endpoint.')

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

TypeScript前端代码(App.tsx)

import React, { useState, useRef } from 'react';

function App() {
  const [recording, setRecording] = useState<Blob | null>(null);
  const [serverResponse, setServerResponse] = useState<string>('');

  const mediaRecorder = useRef<MediaRecorder | null>(null);
  const chunks: Blob[] = [];

  const startRecording = () => {
    navigator.mediaDevices.getUserMedia({ audio: true })
      .then((stream) => {
        mediaRecorder.current = new MediaRecorder(stream);
        mediaRecorder.current.ondataavailable = (event) => {
          if (event.data.size > 0) {
            chunks.push(event.data);
          }
        };
        mediaRecorder.current.onstop = () => {
          const recordedBlob = new Blob(chunks, { type: 'audio/wav' });
          setRecording(recordedBlob);
          chunks.length = 0; // Reset chunks
        };
        mediaRecorder.current.start();
      })
      .catch((error) => console.error('Error starting recording:', error));
  };

  const stopRecording = () => {
    if (mediaRecorder.current) {
      mediaRecorder.current.stop();
      if (recording) {
        sendRecording();
      }
    }
  };

  const sendRecording = async () => {
    try {
      const response = await fetch('/api/receive-recording', {
        method: 'POST',
        body: recording,
      });
      const data = await response.json();
      setServerResponse(data.message);
    } catch (error) {
      console.error('Error sending recording:', error);
    }
  };

  return (
    <div className="App">
      <h1>Audio Recording and Communication</h1>
      {!recording ? (
        <button onClick={startRecording}>Start Recording</button>
      ) : (
        <>
          <button onClick={stopRecording}>Stop Recording and Send</button>
          <audio controls src={URL.createObjectURL(recording)} />
          {serverResponse && <p>Server Response: {serverResponse}</p>}
        </>
      )}
    </div>
  );
}

export default App;

问题原因及修复方案

核心问题:状态更新异步导致sendRecording未被调用

setRecording是React异步状态更新操作,调用mediaRecorder.current.stop()后,onstop回调里执行setRecording(recordedBlob),但此时stopRecording函数里紧接着判断if (recording),这时recording还没更新为新生成的Blob值,所以sendRecording根本没触发。

修复方案(二选一即可)

方案1:将发送逻辑移到onstop回调中

直接在生成录音Blob后调用发送函数,避免依赖异步更新的状态:

// 修改onstop回调
mediaRecorder.current.onstop = () => {
  const recordedBlob = new Blob(chunks, { type: 'audio/wav' });
  setRecording(recordedBlob);
  chunks.length = 0;
  sendRecording(recordedBlob); // 直接传入Blob
};

// 修改sendRecording函数
const sendRecording = async (audioBlob: Blob) => {
  try {
    const response = await fetch('/api/receive-recording', {
      method: 'POST',
      body: audioBlob,
    });
    const data = await response.json();
    setServerResponse(data.message);
  } catch (error) {
    console.error('Error sending recording:', error);
  }
};

// 修改stopRecording函数,移除里面的sendRecording调用
const stopRecording = () => {
  if (mediaRecorder.current) {
    mediaRecorder.current.stop();
  }
};

方案2:用useEffect监听状态变化

通过监听recording状态,当它从null变为Blob时自动触发发送:

// 导入useEffect
import React, { useState, useRef, useEffect } from 'react';

// ... 其他代码 ...

// 添加useEffect监听
useEffect(() => {
  if (recording) {
    sendRecording();
  }
}, [recording]);

// 修改stopRecording函数,移除里面的sendRecording调用
const stopRecording = () => {
  if (mediaRecorder.current) {
    mediaRecorder.current.stop();
  }
};

额外注意事项

  • 跨域问题:如果前端(比如React默认3000端口)和后端(Flask默认5000端口)不在同一端口,需要给Flask添加CORS支持:安装flask-cors,然后在代码中添加:
from flask_cors import CORS
CORS(app)
  • 请求URL正确性:跨域场景下,fetch的URL要写完整地址,比如http://localhost:5000/api/receive-recording

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 17:35:14