一、效果
二、实现分片上传
2.1 开启node服务
- 创建server文件夹,执行npm init
- 安装依赖:yarn add express express-fileupload nodemon
- 创建执行命令:"dev": "nodemon ./app.js"
- 创建app.js(提供一个上传接口)和files(存储客户端上传的文件)
app.js
const express = require('express')
const uploader = require('express-fileupload')
const bodyParser = require('body-parser')
const { extname, resolve } = require('path')
const { existsSync, appendFileSync, writeFileSync } = require('fs')
const app = express()
const PORT = 8008
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())
app.use(uploader())
app.use('/', express.static('files'))
const ALLOWED_TYPE = { 'video/mp4': 'mp4', 'video/ogg': 'ogg' }
// 跨域
app.all('*', (req, res, next) => {
res.header('Access-Control-Allow-origin', '*')
res.header('Access-Control-Allow-Methods', 'POST,GET')
next()
})
app.post('/upload_video', (req, res) => {
const { name, type, size, fileName, uploadSize } = req.body
const { file } = req.files
if (!file) {
req.send({ code: 1001, msg: '未上传文件' })
return
}
if (!ALLOWED_TYPE[type]) {
res.send({ code: 1002, msg: '类型不符合规定' })
return
}
const filename = fileName + extname(name)
const filePath = resolve(__dirname, `./files/${filename}`)
if (uploadSize !== '0') {
if (!existsSync(filePath)) {
res.send({ code: 1003, msg: '文件不存在' })
return
}
appendFileSync(filePath, file.data)
res.send({ code: 0, msg: '追加成功', video_url: `http://localhost:8008/${filename}` })
return
}
writeFileSync(filePath, file.data)
res.send({ code: 0, msg: '文件已创建', video_url: `http://localhost:8008/${filename}` })
})
app.listen(PORT, () => {
console.log('服务已启动,端口号:', PORT)
})
终端执行npm run dev
2.2 创建BigFile组件
<template>
<div class="">
上传进度:<progress :value="progressValue" :max="pregressMax" />
<input ref="inputRef" type="file" />
<el-button @click="handleUpload">上传</el-button>
</div>
</template>
<script>
const CHUNK_SIZE = 1024 * 1024
import axios from 'axios'
export default {
name: 'BigFile',
data() {
return {
progressValue: 0,
pregressMax: 1,
uploadSize: 0
}
},
created() {},
methods: {
async handleUpload() {
const [file] = this.$refs.inputRef.files
if (!file) {
return this.$message.warning('请先选择文件')
}
const { name, type, size } = file
if (type !== 'video/mp4') {
return this.$message.warning('文件格式不对')
}
const fileName = Date.now() + '_' + name
let uploadResult = null
this.pregressMax = size
while (this.uploadSize < size) {
const fileChunk = file.slice(this.uploadSize, this.uploadSize + CHUNK_SIZE)
const formData = this.createFormData({ name, type, size, fileName, uploadSize: this.uploadSize, file: fileChunk })
try {
uploadResult = await axios.post('http://localhost:8008/upload_video', formData)
} catch (e) {
return this.$message.error('上传失败:' + e.message)
}
this.uploadSize += fileChunk.size
this.progressValue = this.uploadSize
}
console.log('uploadResult', uploadResult)
this.createVideo(uploadResult.data.video_url)
},
createFormData({ name, type, size, fileName, uploadSize, file }) {
const fd = new FormData()
fd.append('name', name)
fd.append('type', type)
fd.append('size', size)
fd.append('fileName', fileName)
fd.append('uploadSize', uploadSize)
fd.append('file', file)
return fd
},
createVideo(src) {
const oVideo = document.createElement('video')
oVideo.controls = true
oVideo.width = '300'
oVideo.src = src
document.querySelector('#app').appendChild(oVideo)
}
}
}
</script>