React项目调用Node.js保存录音时出现Uncaught (in promise) AxiosError求助
问题分析与修正方案
你的代码存在几个关键问题,导致Axios请求失败和音频无法正确保存:
1. React端(Record.js)的错误修正
核心问题:
- 请求URL缺少
http://协议,浏览器会将其当作相对路径处理 - 上传的是
blobURL(本地URL字符串)而非实际的Blob音频文件,multer无法解析 - 未捕获Axios请求错误,无法定位具体问题
- 提前弹出成功提示,无视请求实际状态
修正后的完整代码:
import React from "react"; import MicRecorder from "mic-recorder-to-mp3"; import { Button } from "reactstrap"; import "./App.css"; import Navbar from "./Navbar"; import mic from "./imgs/mic.png"; import stop from "./imgs/stop.png"; import axios from "axios"; const Mp3Recorder = new MicRecorder({ bitRate: 128 }); class Record extends React.Component { constructor(props) { super(props); this.state = { isRecording: false, blobURL: "", isBlocked: false, audioBlob: null, // 新增:存储原始Blob音频对象 }; } start = () => { if (this.state.isBlocked) { console.log("Permission Denied"); } else { Mp3Recorder.start() .then(() => this.setState({ isRecording: true })) .catch((e) => console.error(e)); } }; stop = () => { Mp3Recorder.stop() .getMp3() .then(([buffer, blob]) => { const blobURL = URL.createObjectURL(blob); this.setState({ blobURL, isRecording: false, audioBlob: blob }); // 保存原始Blob }) .catch((e) => console.log(e)); }; componentDidMount() { // 替换废弃的getUserMedia API navigator.mediaDevices.getUserMedia({ audio: true }) .then(() => { console.log("Permission Granted"); this.setState({ isBlocked: false }); }) .catch(() => { console.log("Permission Denied"); this.setState({ isBlocked: true }); }); } Save = async (e) => { e.preventDefault(); if (!this.state.audioBlob) { alert("请先录制音频"); return; } const url = "http://localhost:8000/record"; // 补充完整协议 const data = new FormData(); // 上传原始Blob对象,并指定文件名 data.append("audio", this.state.audioBlob, `recording_${Date.now()}.mp3`); try { const response = await axios.post(url, data, { headers: { "Content-Type": "multipart/form-data" }, }); console.log("上传成功", response.data); alert("音频上传成功"); } catch (error) { console.error("上传失败", error); alert("音频上传失败,请检查服务器是否运行"); } }; render() { return ( <div className="big-wrapper light"> <div className="container"> <Navbar /> <br /> <br /> <br /> <div className="cont1"> <h2 style={{ color: "white", marginLeft: "-98px" }}> Remove Noise From Your Audio </h2> <br /> <Button className="bg-transparent border btn record-button rounded-circle shadow-sm text-center" id="recordButton" onClick={() => { this.state.isRecording ? this.stop() : this.start(); }} > {this.state.isRecording ? <img src={stop} /> : <img src={mic} />} </Button> <br /> <br /> <audio src={this.state.blobURL} controls="controls" autoPlay id="audio-element" /> <br /> <br /> <form method="post" action="#" onSubmit={this.Save} className="form-group" > <button className="btn-recordaudio">Submit</button> </form> </div> </div> </div> ); } } export default Record;
2. Node.js端(index.js)的错误修正
核心问题:
- 上传Blob时
file.originalname不存在,导致文件名处理出错 - 未检查uploads目录是否存在,可能导致保存失败
- 缺少文件上传失败的错误处理
修正后的完整代码:
const path = require("path"); const fs = require("fs"); const express = require("express"); const multer = require("multer"); const cors = require("cors"); const app = express(); app.use(cors()); app.use(express.static("uploads")); // 确保uploads目录存在,不存在则创建 const uploadDir = path.join(__dirname, "uploads"); if (!fs.existsSync(uploadDir)) { fs.mkdirSync(uploadDir, { recursive: true }); } const storage = multer.diskStorage({ destination(req, file, cb) { cb(null, uploadDir); }, filename(req, file, cb) { // 处理无原始文件名的情况,默认使用mp3后缀 const ext = path.extname(file.originalname) || ".mp3"; // 生成唯一文件名,避免覆盖 cb(null, `recording_${Date.now()}${ext}`); }, }); const upload = multer({ storage }); app.post("/record", upload.single("audio"), (req, res) => { if (!req.file) { return res.status(400).json({ success: false, message: "未检测到音频文件" }); } res.json({ success: true, filePath: `/uploads/${req.file.filename}` }); }); app.listen(8000, () => { console.log("server is running on http://localhost:8000"); });
3. 测试步骤
- 在Node.js服务器目录运行
node index.js启动服务 - 启动React项目,录制一段音频
- 点击Submit按钮,检查uploads目录是否生成音频文件
- 查看浏览器控制台,确认无报错信息
内容的提问来源于stack exchange,提问作者Steven
相关产品推荐
相关产品推荐

