React Native Expo调用Flask API遇Network Request Failed问题求助
问题:React Native Expo调用Flask语音转写API报"Network Request Failed"
React Native Expo应用通过本地IP调用Node.js API时,模拟器和实体Android设备均正常,但调用同局域网内的Flask语音转写API时,出现"Network Request Failed"错误。Flask API部署在本地机器(地址:http://192.168.x.x:5000),实体Android设备与电脑连接同一WiFi网络。
Flask API代码
from flask import Flask, request, jsonify import base64 import tempfile import speech_recognition as sr from pydub import AudioSegment from io import BytesIO from flask_cors import CORS import logging app = Flask(__name__) CORS(app, resources={ r"/*": { "origins": "*", "methods": ["GET", "POST", "OPTIONS"], "allow_headers": ["Content-Type", "uthorization"] } }) logging.basicConfig(level=logging.DEBUG) def transcribe_audio(audio_base64): # Decode the base64 audio data try: audio_data = base64.b64decode(audio_base64) except Exception as e: return f"Error decoding base64 audio: {str(e)}" # Convert base64 audio to a format that SpeechRecognition can use (WAV) audio_file = BytesIO(audio_data) audio = AudioSegment.from_file(audio_file) # Create a temporary file to store the WAV audio with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as temp_file: audio.export(temp_file.name, format="wav") temp_file_path = temp_file.name # Use SpeechRecognition to transcribe the audio recognizer = sr.Recognizer() try: with sr.AudioFile(temp_file_path) as source: audio_listened = recognizer.record(source) transcription = recognizer.recognize_google(audio_listened) return transcription except Exception as e: return f"Error transcribing audio: {str(e)}" @app.route('/health',methods=['GET']) def health(): logging.info("Health check endpoint called") return "Hello world from python" @app.route('/transcribe', methods=['POST']) def transcribe(): # Get the base64 audio data from the POST request print("here") data = request.json print(data) if not data or 'audio_base64' not in data: return jsonify({"error": "Missing audio_base64 in request"}), 400 audio_base64 = data['audio_base64'] # Transcribe the audio transcription = transcribe_audio(audio_base64) if "Error" in transcription: return jsonify({"error": transcription}), 500 return jsonify({"transcription": transcription}), 200 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True,threaded=True)
React Native Expo代码
import { Audio } from "expo-av"; import { MutableRefObject } from "react"; import * as Filesystem from "expo-file-system"; import { Platform } from "react-native"; import * as Device from "expo-device"; import axios from "axios" export const transcribeSpeechAssembly = async ( audioRecordingRef: MutableRefObject<Audio.Recording> ) => { const isPrepared = audioRecordingRef?.current?._canRecord; if (!isPrepared) { console.error("Recording must be prepared first"); return undefined; } try { await audioRecordingRef?.current?.stopAndUnloadAsync(); const recordingUri = audioRecordingRef?.current?.getURI() || ""; const baseUri = await Filesystem.readAsStringAsync(recordingUri, { encoding: Filesystem.EncodingType.Base64 }); const rootOrigin = Platform.OS === "android" ? "My local IP" : Device.isDevice ? process.env.LOCAL_DEV_IP || "localhost" : "localhost"; const serverUrl = `http://${rootOrigin}:5000`; if (recordingUri && baseUri) { console.log("url",`${serverUrl}/transcribe`) const api = axios.create({ baseURL: serverUrl, timeout: 10000, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }); try { const healthCheck = await api.get('/health'); console.log("Health check response:", healthCheck.data); const transcriptionResponse = await api.post('/transcribe', { audio_base64: baseUri }); console.log("Transcription response:", transcriptionResponse.data); return transcriptionResponse.data?.transcription; } catch (error) { console.error("error from python server",error) } } else { console.error("Something went wrong with recording"); return undefined; } } catch (error) { console.error("Error in transcription process:", error); return undefined; } };
已尝试的排查步骤
- 确认Flask API正常运行:Postman和浏览器访问
http://127.0.0.1:5000/health和http://192.168.x.x:5000/health均返回"Hello world from python"; - 检查Expo网络请求:Node.js API(
http://192.168.x.x:3000)能正常调用,但Flask的/transcribe接口返回"Network Request Failed"; - 配置Flask接受外部连接:使用
app.run(host='0.0.0.0', port=5000, debug=True, threaded=True); - 处理CORS问题:通过flask_cors允许所有来源;
- 验证Android权限:AndroidManifest.xml已添加
<uses-permission android:name="android.permission.INTERNET" />; - 尝试adb反向代理:实体设备无效果;
- 关闭防火墙/杀毒软件:无改善;
- Chrome调试器查看:fetch请求失败,提示"Network Request Failed"。
排查与解决方案
1. 调整请求超时与Flask请求大小限制
语音转写的base64数据通常体积较大,当前10秒超时可能不足,且Flask默认1MB的请求大小限制容易被突破:
- React Native端延长axios超时时间:
const api = axios.create({ baseURL: serverUrl, timeout: 30000, // 改为30秒 headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }); - Flask端设置更大的请求容量:
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 允许16MB请求
2. 清理base64数据前缀
Expo录制的音频转base64后可能带有data:audio/xxx;base64,前缀,导致Flask解码失败,需先移除:
let baseUri = await Filesystem.readAsStringAsync(recordingUri, { encoding: Filesystem.EncodingType.Base64 }); // 移除data URI前缀 baseUri = baseUri.replace(/^data:audio\/[^;]+;base64,/, '');
3. 增强Flask日志捕获
修改Flask的/transcribe接口,用logging替代print,便于排查请求是否到达及具体错误:
@app.route('/transcribe', methods=['POST']) def transcribe(): logging.debug("Transcribe endpoint triggered") try: data = request.json logging.debug(f"Received request keys: {data.keys() if data else 'No JSON data'}") if not data or 'audio_base64' not in data: return jsonify({"error": "Missing audio_base64 in request"}), 400 audio_base64 = data['audio_base64'] transcription = transcribe_audio(audio_base64) if "Error" in transcription: return jsonify({"error": transcription}), 500 return jsonify({"transcription": transcription}), 200 except Exception as e: logging.error(f"Server error in transcribe: {str(e)}") return jsonify({"error": f"Server error: {str(e)}"}), 500
4. 测试简化请求
先用一段短音频的base64字符串测试接口,排除大文件问题:
// 替换为短测试音频的base64 const testAudioBase64 = "UklGRkoQAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA"; const transcriptionResponse = await api.post('/transcribe', { audio_base64: testAudioBase64 });
5. 配置Android明文HTTP访问
Android 9及以上默认禁止明文HTTP请求,需在Expo的app.json中开启:
{ "expo": { "android": { "usesCleartextTraffic": true, // 其他Android配置 } } }
内容的提问来源于stack exchange,提问作者Nisarg jadhav
相关产品推荐
相关产品推荐

