背景背景背景我在开发小程序的时候,有需求要实现录音功能,并能上传给服务器。小程序录音功能我是使用的微信的wx.getRecorderManager()实现的,通过该方法创建实例,实例录音得到的文件是本地临时文件,上传文件需要使用微信的wx.uploadFile(Object object)方法,这就是本次项目的背景。wx.getRecorderManager()wx.uploadFile(Object object)小程序端小程序端小程序端html页面主要是第一个按钮,两个事件,长按开始录音,松手停止录音。第二个按钮只是一个播放录音的功能,用于确定录音是否成功





js部分主要就是两个事件
// pages/record/record.js
// 两个实例声明在Page之外,方便访问
const recorderManager = wx.getRecorderManager() //这是录音功能的实例,必须的
const innerAudioContext = wx.createInnerAudioContext(); //这是播放录音功能需要的实例
Page({
data: {
tempFilePath: '' //存放录音文件的临时路径
},
// 播放录音
playVoice: function(e) {
innerAudioContext.onPlay(() => {
console.log('开始播放')
})
innerAudioContext.onError((res) => {
console.log(res.errMsg)
console.log(res.errCode)
})
innerAudioContext.play();
},
// 录音
beginRecord:function(e) {
// 监听录音开始事件
recorderManager.onStart(() => {
console.log('recorder start')
})
// 监听已录制完指定帧大小的文件事件。如果设置了 frameSize,则会回调此事件。
recorderManager.onFrameRecorded((res) => {
const { frameBuffer } = res
console.log('frameBuffer.byteLength', frameBuffer.byteLength)
})
//录音的参数
const options = {
duration: 60000, //录音时间,默认是60s,提前松手会触发button的bindtouchend事件,执行停止函数并上传录音文件。超过60s不松手会如何并未测试过
sampleRate: 44100,
numberOfChannels: 1,
encodeBitRate: 192000,
format: 'mp3', //录音格式,这里是mp3
frameSize: 50 //指定帧大小,单位 KB。传入 frameSize 后,每录制指定帧大小的内容后,会回调录制的文件内容,不指定则不会回调。暂仅支持 mp3 格式。
}
//开始录音
recorderManager.start(options);
},
//停止录音并上传数据
endRecord:function(e) {
const self = this;
//停止录音
recorderManager.stop();
//监听录音停止事件,执行上传录音文件函数
recorderManager.onStop((res) => {
console.log('recorder stop', res)
//返回值res.tempFilePath是录音文件的临时路径 (本地路径)
self.setData({
tempFilePath: res.tempFilePath
})
innerAudioContext.src = res.tempFilePath
//上传录音文件
var uploadTask = wx.uploadFile({
//没有method,自动为POST请求
filePath: res.tempFilePath,
name: 'recordFile',
//这个随便填
url: 'http://localhost:3000/record', //填写自己服务器的地址。
header: {
"Content-Type": "multipart/form-data" //必须是这个格式
},
success:(e) => {
console.log('succeed!');
console.log(e);
},
fail: (e) => {
console.log('failed!');
console.log(e);
}
});
uploadTask.onProgressUpdate((e) => {
console.log(e);
console.log('期望上传的总字节数:' + e.totalBytesExpectedToSend);
console.log('已经上传的字节数' + e.totalBytesSent);
})
})
}
})
// pages/record/record.js
// 两个实例声明在Page之外,方便访问
const recorderManager = wx.getRecorderManager() //这是录音功能的实例,必须的
const innerAudioContext = wx.createInnerAudioContext(); //这是播放录音功能需要的实例
Page({
data: {
tempFilePath: '' //存放录音文件的临时路径
},
// 播放录音
playVoice: function(e) {
innerAudioContext.onPlay(() => {
console.log('开始播放')
})
innerAudioContext.onError((res) => {
console.log(res.errMsg)
console.log(res.errCode)
})
innerAudioContext.play();
},
// 录音
beginRecord:function(e) {
// 监听录音开始事件
recorderManager.onStart(() => {
console.log('recorder start')
})
// 监听已录制完指定帧大小的文件事件。如果设置了 frameSize,则会回调此事件。
recorderManager.onFrameRecorded((res) => {
const { frameBuffer } = res
console.log('frameBuffer.byteLength', frameBuffer.byteLength)
})
//录音的参数
const options = {
duration: 60000, //录音时间,默认是60s,提前松手会触发button的bindtouchend事件,执行停止函数并上传录音文件。超过60s不松手会如何并未测试过
sampleRate: 44100,
numberOfChannels: 1,
encodeBitRate: 192000,
format: 'mp3', //录音格式,这里是mp3
frameSize: 50 //指定帧大小,单位 KB。传入 frameSize 后,每录制指定帧大小的内容后,会回调录制的文件内容,不指定则不会回调。暂仅支持 mp3 格式。
}
//开始录音
recorderManager.start(options);
},
//停止录音并上传数据
endRecord:function(e) {
const self = this;
//停止录音
recorderManager.stop();
//监听录音停止事件,执行上传录音文件函数
recorderManager.onStop((res) => {
console.log('recorder stop', res)
//返回值res.tempFilePath是录音文件的临时路径 (本地路径)
self.setData({
tempFilePath: res.tempFilePath
})
innerAudioContext.src = res.tempFilePath
//上传录音文件
var uploadTask = wx.uploadFile({
//没有method,自动为POST请求
filePath: res.tempFilePath,
name: 'recordFile',
//这个随便填
url: 'http://localhost:3000/record', //填写自己服务器的地址。
header: {
"Content-Type": "multipart/form-data" //必须是这个格式
},
success:(e) => {
console.log('succeed!');
console.log(e);
},
fail: (e) => {
console.log('failed!');
console.log(e);
}
});
uploadTask.onProgressUpdate((e) => {
console.log(e);
console.log('期望上传的总字节数:' + e.totalBytesExpectedToSend);
console.log('已经上传的字节数' + e.totalBytesSent);
})
})
}
})到这里,小程序部分的代码就已经完成了。node服务器端node服务器端node服务器端前提:node服务器我是用的是 express 框架,如果有不会的朋友,可以先简单了解一下express。
要后端能解析用户上传的文件,需要合适的中间件。可以参考文章末尾的讲解nodejs使用connect-multiparty实现文件上传(文件接收)后端。
首先项目需要安装 express 和 connect-multipartyexpressnodejs使用connect-multiparty实现文件上传(文件接收)后端nodejs使用connect-multiparty实现文件上传(文件接收)后端
npm install express

npm install connnect-multiyparty
npm install express

npm install connnect-multiyparty大家学node的,上面两句不应该看不懂。我不加 --save 是因为新版的node和npm不需要加就会给你保存在package.json文件内。
//这是我的路由文件的代码片段,监听端口号3000等设置在我的另一个文件内。
//这只是代码片段,大概率跑不起来,只起一个demo的作用。如果需要完整的代码,可以留言给我。

const express = require('express');
const multiparty = require('connect-multiparty');

var router = express.Router();
var multipartMiddleware = multiparty();
router.use(multiparty({uploadDir:'./temp'})); //将接收文件的地址更改为当前目录下的temp文件夹。如果没有,则需要新建该文件夹。

// 处理录音文件
//只需要这样处理,上传的MP3文件就会保存在指定的目录下了。
router.post('/record', multipartMiddleware, (request, response) => {
console.log('received a request');
console.log(request.files);
request.on('end', () => {
response.send('通信完成');
})

})
//这是我的路由文件的代码片段,监听端口号3000等设置在我的另一个文件内。
//这只是代码片段,大概率跑不起来,只起一个demo的作用。如果需要完整的代码,可以留言给我。

const express = require('express');
const multiparty = require('connect-multiparty');

var router = express.Router();
var multipartMiddleware = multiparty();
router.use(multiparty({uploadDir:'./temp'})); //将接收文件的地址更改为当前目录下的temp文件夹。如果没有,则需要新建该文件夹。

// 处理录音文件
//只需要这样处理,上传的MP3文件就会保存在指定的目录下了。
router.post('/record', multipartMiddleware, (request, response) => {
console.log('received a request');
console.log(request.files);
request.on('end', () => {
response.send('通信完成');
})

})郑重提示:保存下来的是临时文件,短时间内就会自动删除,所以大家需要及时处理文件,比如写入到新文件中这个框架已经两年没更新了,所以这个框架这不一定是好的,但是是可行的下面看下nodejs使用connect-multiparty实现文件上传(文件接收)后端下面看下nodejs使用connect-multiparty实现文件上传(文件接收)后端下面看下nodejs使用connect-multiparty实现文件上传(文件接收)后端文件上传文件上传文件上传是服务器经常会用到的一项功能。做了几次文件上传功能,发现文件接收后端还是没那么容易。尝试过不同的中间件,折腾来折腾去,发现connect-multiparty用起来比较简单,适配nodejs版本v0.12.11。用法用法
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();
app.post('/upload', multipartMiddleware, function(req, resp) {
console.log(req.body, req.files);
// don't forget to delete all req.files when done
});
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();
app.post('/upload', multipartMiddleware, function(req, resp) {
console.log(req.body, req.files);
// don't forget to delete all req.files when done
});前端用multipart/form-data的形式上传数据,后端通过中间件connect-multipary接收。
注意,接收结果req.files是一个对象,包含POST上传的参数和一个临时文件,文件一般在/tmp目录下,可以将文件移动到指定位置。
var fs = require('fs');
var source = fs.createReadStream(path);
var dest = fs.createWriteStream(output);
source.pipe(dest);
source.on('end', function() { fs.unlinkSync(path);}); //delete
source.on('error', function(err) { });
var fs = require('fs');
var source = fs.createReadStream(path);
var dest = fs.createWriteStream(output);
source.pipe(dest);
source.on('end', function() { fs.unlinkSync(path);}); //delete
source.on('error', function(err) { });参考
connect-multiparty
connect-multiparty总结总结总结