vue2 + egg.js使用FormData传递表单和文件(上传音频)
使用formdata上传音频,egg接收音频文件,存入项目目录
·
本篇博客适合了解vue项目、了解eggjs、了解axios的小伙伴阅读,如果不是熟悉这些技术,可以先去看看相关视频或者网站学习。
一份表单中包含有普通参数、也有要上传的文件,将这些数据放到formdata中传递到后端进行处理。
我这里的前端用的是vue2,页面仅有一个表单,页面的代码如下:
<template>
<div class="about">
<el-form :model="form"
status-icon
label-width="100px"
class="demo-ruleForm">
<el-form-item label="内容"
prop="content">
<el-input type="text"
v-model="form.content"
autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="文件"
prop="audio">
<el-upload class="avatar-uploader"
action=""
:show-file-list="false"
:before-upload="beforeUpload"
:on-change="change">
上传
</el-upload>
<audio :src="audioSrc"
controls="controls" />
<div>{{filename}}</div>
</el-form-item>
<el-form-item>
<el-button type="primary"
@click="submitForm">提交</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import $api from "../utils/api";
export default {
data: () => {
return {
filename: "",
form: { content: "" },
fileBase64: "",
audioSrc: "",
formdata: new FormData(),
};
},
watch: {},
mounted() {},
methods: {
change(file) {
console.log(file);
const isMp3 = file.raw.type === "audio/mpeg";
if (!isMp3) {
return 0;
} else {
//这的file并不是我们真正要传递的file,file.raw才是
this.formdata.append("upfile", file.raw); //将file.raw放到formdata中
this.formdata.append("filename", file.raw.name); //将文件名也放到formdata中
this.filename = file.raw.name;
this.base64_encode(file.raw); //调用base64_encode函数
}
},
//传入file,将文件转为blob类型
base64_encode(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
// console.log("file 转 base64结果:" + reader.result); //reader.result是base64码,但是因为音频较长的时候,需要转为blob才能播放
this.fileBase64 = reader.result;
let audioBlob = this.base64ToBlob(this.fileBase64, "mp3"); //将base64转为Blob
this.audioSrc = window.URL.createObjectURL(audioBlob); //设置页面上的音频的src
};
},
//将base64转为blob
base64ToBlob(base64, type) {
let arr = base64.split(",");
let array = arr[0].match(/:(.*?);/); //arr[0]是base64的开头说明
let mime = (array && array.length > 1 ? array[1] : type) || type;
let bytes = window.atob(arr[1]); //arr[1]是完整的base64码 window.atob()返回一个解码后的字符串
// console.log(bytes);
let abuffer = new ArrayBuffer(bytes.length); //二进制的数据缓冲区
// console.log(Object.prototype.toString.call(abuffer));
let u8a = new Uint8Array(abuffer);
for (let i = 0; i < bytes.length; i++) {
u8a[i] = bytes.charCodeAt(i);
}
return new Blob([abuffer], {
type: mime,
}); //最后返回一个Blob数据
},
beforeUpload(file) {
const isMp3 = file.type === "audio/mpeg";
if (!isMp3) {
this.$message.error("上传头像图片只能是 mp3 格式!");
}
return false;
},
submitForm() {
this.formdata.append("content", this.form.content); //模拟的表单普通文本
$api
.post("/audio", this.formdata) //请求后egg端接口/audio并把formdata传过去
.then((res) => {
console.log(res); //得到结果
if (res.data.status == 1) {
//存入成功
this.$message({
message: "提交成功",
duration: 1000,
type: "success",
});
this.formdata = new FormData(); //重新设置formdata
} else {
this.$message({
message: "提交失败",
duration: 1000,
type: "error",
});
}
})
.catch((e) => {
console.log(e);
});
},
},
};
</script>
前端使用的是axios来发起请求,因为我们使用FormData传递文件数据,所以需要设置请求头中的content-type为 “multipart/form-data”
import axios from "axios";
const $api = axios.create({ baseURL: "http://127.0.0.1:7001" })
$api.interceptors.request.use(function (config) {
config.headers['content-type'] = "multipart/form-data";
return config;
}, function (error) {
return Promise.reject(error);
});
export default $api;
egg后端代码,先在config.default.js中设置multipart,这里的设置官网有,但是官网只写了mode:“file”,我使用的时候,系统会报错。
这里设置一下文件大小,我设置到100mb大,可以上传小于100mb的文件。
文件类型我只做了MP3的例子,根据需要修改。
config.multipart = {
// mode: "file",
fileSize: '100mb',
mode: 'stream',
fileExtensions: ['.mp3'], // 扩展几种上传的文件格式
};
router.js文件中设置接口路由
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.post('/audio', controller.home.uploadAudio);
};
控制器中写入uploadAudio方法,egg需要安装await-stream-ready、stream-wormhole、formidable插件
'use strict';
const Controller = require('egg').Controller;
const fs = require('fs');
const path = require('path');
const awaitWriteStream = require('await-stream-ready').write;
const sendToWormhole = require('stream-wormhole');
const audioBaseUrl = 'app/public/audio';//这是我的音频存放位置
const formidable = require("formidable");
class HomeController extends Controller {
async uploadAudio() {
const { ctx } = this;
try {
function parse(req) {//使用formidable解析formdata
const form = new formidable.IncomingForm();
return new Promise((resolve, reject) => {
form.parse(req, (err, fields, files) => {
resolve({ fields, files });
reject((res) => { console.log(res) })
});
});
}
const extraParams = await parse(this.ctx.req);
console.log("FormData中的普通参数-----------", extraParams.fields);
console.log("FormData中的文件--------------", extraParams.files);
const file = extraParams.files.upfile; //得到文件upfile,我的vue传过来的file就叫做upfile,所以这里取出来也是通upfile
const stream = fs.createReadStream(file._writeStream.path);//创建文件读取流,从临时文件中读取
const fileName = extraParams.fields.filename;//文件命名
//为保证文件的命名不重复,结合自己的项目数据库的需要,取时间戳加用户id或者其他方式
const target = path.join(audioBaseUrl, fileName);//目标路径
const writeStream = fs.createWriteStream(target);//将问价写入目标路径
try {
await awaitWriteStream(stream.pipe(writeStream));//等待完成写入
} catch (err) {
await sendToWormhole(stream);//关闭临时文件
console.log(err)
}
ctx.body = { status: 1 }
} catch (err) {
console.log(err)
ctx.body = { status: 0 }
}
}
}
module.exports = HomeController;
页面显示如下:
点击“上传”,即可选择文件,选好MP3文件后,页面可以进行播放。
egg中就可以打印出这些信息了:
并且将音频文件存入到指定的目录中
更多推荐
已为社区贡献1条内容
所有评论(0)