<template>
<div id="app">
<h1>App3</h1>
<el-upload drag action :auto-upload="false" :show-file-list="false" :on-change="changeFile" :on-success="handleSuccess">
<i class="el-icon-upload"></i>
<div class="el-upload__text">
大文件的断点续传将文件拖到此处,或
<em>点击上传</em>
</div>
</el-upload>
<!-- PROGRESS -->
<div class="progress">
<span>上传进度:{{total|totalText}}%</span>
<el-link type="primary" v-if="total>0 && total<100" @click="handleBtn">{{btn|btnText}}</el-link>
</div>
<!-- VIDEO -->
<div class="uploadImg" v-if="video">
<video :src="video" controls />
</div>
</div>
</template>
<script>
import { fileParse } from "./assets/utils";
import axios from "axios";
import SparkMD5 from "spark-md5";
export default {
name: "App",
data() {
return {
total: 0,
video: null,
btn: false,
abort :false
};
},
filters: {
btnText(btn) {
return btn ? "继续" : "暂停";
},
totalText(total) {
return total > 100 ? 100 : total;
},
},
methods: {
handleSuccess(){
console.log(1)
},
async changeFile(file) {
console.log('file',file)
if (!file) return;
file = file.raw;
console.log('file→',file)
let buffer = await fileParse(file, "buffer"),
spark = new SparkMD5.ArrayBuffer(),
hash,
suffix;
spark.append(buffer);
hash = spark.end();
suffix = /\.([0-9a-zA-Z]+)$/i.exec(file.name)[1];
let partList = [],
partsize = file.size / 100,
cur = 0;
for (let i = 0; i < 100; i++) {
let item = {
chunk: file.slice(cur, cur + partsize),
filename: `${hash}_${i}.${suffix}`,
};
cur += partsize;
partList.push(item);
}
this.partList = partList;
this.hash = hash;
this.sendRequest();
},
async sendRequest() {
let requestList = [];
this.partList.forEach((item, index) => {
let fn = () => {
let formData = new FormData();
formData.append("chunk", item.chunk);
formData.append("filename", item.filename);
return axios
.post("/single3", formData, {
headers: { "Content-Type": "multipart/form-data" },
})
.then((result) => {
result = result.data;
if (result.code == 0) {
this.total += 1;
this.partList.splice(index, 1);
}
});
};
requestList.push(fn);
});
let i = 0;
let complete = async () => {
let result = await axios.get("/merge", {
params: {
hash: this.hash,
},
});
result = result.data;
if (result.code == 0) {
this.video = result.path;
}
alert("文件上传完毕!")
};
let send = async () => {
if (this.abort) return;
if (i >= requestList.length) {
complete();
return;
}
await requestList[i]();
i++;
send();
};
send();
},
handleBtn() {
if (this.btn) {
this.abort = false;
this.btn = false;
this.sendRequest();
return;
}
this.btn = true;
this.abort = true;
},
},
};
</script>
serverjs
const express = require('express'),
app = express(),
bodyParser = require('body-parser'),
fs = require('fs'),
SparkMD5 = require('spark-md5'),
PORT = 8888;
app.listen(PORT, () => {
console.log(`THE WEB SERVICE IS CREATED SUCCESSFULLY AND IS LISTENING TO THE PORT:${PORT}`);
});
app.use(bodyParser.urlencoded({
extended: false,
limit: '1024mb'
}));
const multiparty = require("multiparty"),
uploadDir = `${__dirname}/upload`;
function handleMultiparty(req, res, temp) {
return new Promise((resolve, reject) => {
let options = {
maxFieldsSize: 200 * 1024 * 1024
};
!temp ? options.uploadDir = uploadDir : null;
let form = new multiparty.Form(options);
form.parse(req, function (err, fields, files) {
if (err) {
res.send({
code: 1,
reason: err
});
reject(err);
return;
}
resolve({
fields,
files
});
});
});
}
app.post('/single1', async (req, res) => {
console.log("req",req)
let {
files
} = await handleMultiparty(req, res);
let file = files.file[0];
console.log('file.originalFilename→',file.originalFilename);
console.log('file.path→',file.path);
res.send({
code: 0,
originalFilename: file.originalFilename,
path: file.path.replace(__dirname, `http://127.0.0.1:${PORT}`)
});
});
app.post('/single2', (req, res) => {
let {
chunk,
filename
} = req.body;
chunk = decodeURIComponent(chunk);
chunk = chunk.replace(/^data:image\/\w+;base64,/, "");
chunk = Buffer.from(chunk, 'base64');
let spark = new SparkMD5.ArrayBuffer(),
suffix = /\.([0-9a-zA-Z]+)$/.exec(filename)[1],
path;
spark.append(chunk);
path = `${uploadDir}/${spark.end()}.${suffix}`;
const dir=`${uploadDir}`
const files=fs.readdirSync(dir)
console.log("files→",files)
var arr=[]
files.forEach(function(item){
if(item==`${spark.end()}.${suffix}`){
arr.push(item)
}
})
if(arr.length==0){
fs.writeFileSync(path, chunk);
}
res.send({
code: 0,
originalFilename: filename,
path: path.replace(__dirname, `http://127.0.0.1:${PORT}`)
});
});
app.post('/single3', async (req, res) => {
let {
fields,
files
} = await handleMultiparty(req, res, true);
let [chunk] = files.chunk,
[filename] = fields.filename;
let hash = /([0-9a-zA-Z]+)_\d+/.exec(filename)[1],
path = `${uploadDir}/${hash}`;
!fs.existsSync(path) ? fs.mkdirSync(path) : null;
path = `${path}/${filename}`;
fs.access(path, async err => {
if (!err) {
res.send({
code: 0,
path: path.replace(__dirname, `http://127.0.0.1:${PORT}`)
});
return;
}
let readStream = fs.createReadStream(chunk.path),
writeStream = fs.createWriteStream(path);
readStream.pipe(writeStream);
readStream.on('end', function () {
fs.unlinkSync(chunk.path);
res.send({
code: 0,
path: path.replace(__dirname, `http://127.0.0.1:${PORT}`)
});
});
});
});
app.get('/merge', (req, res) => {
let {
hash
} = req.query;
let path = `${uploadDir}/${hash}`,
fileList = fs.readdirSync(path),
suffix;
fileList.sort((a, b) => {
let reg = /_(\d+)/;
return reg.exec(a)[1] - reg.exec(b)[1];
}).forEach(item => {
!suffix ? suffix = /\.([0-9a-zA-Z]+)$/.exec(item)[1] : null;
fs.appendFileSync(`${uploadDir}/${hash}.${suffix}`, fs.readFileSync(`${path}/${item}`));
fs.unlinkSync(`${path}/${item}`);
});
fs.rmdirSync(path);
res.send({
code: 0,
path: `http://127.0.0.1:${PORT}/upload/${hash}.${suffix}`
});
});
app.use(express.static('./'));
app.use((req, res) => {
res.status(404);
res.send('NOT FOUND!');
});