分片上传文件webuploader

574 阅读1分钟

实现原理

  1. 前端通过webuploader 把文件切成多个小文件
  2. 批量上传的调用后台接口
  3. 当前端发现文件都全部上传完后,通知服务器合并文件,调用merge合并
  4. 合并后保存到服务器

上传后的效果

image.png

实现代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>upload img</title>
    <link rel="stylesheet" href="/assert/css/webuploader.css" />
    <script src="/assert/js/jquery.js"></script>
    <script src="/assert/js/webuploader.html5only.js"></script>
</head>
<body>
<a href="javascript:;" id="upload">上传</a>
<script>
    var guid = WebUploader.guid();
    var chunks = null;
    var ext = null;
	var uploader = WebUploader.create({

		auto: true,
		server: '/upload',
		pick: '#upload',
        chunked: true,
        chunkSize: 1024 * 10,
		chunkRetry: 3,
		thread: 5,
        formData: {
			guid,
        }
	});
	uploader.on( 'uploadAccept', function( file, response ) {
		console.log('uploadAccept',response.flag)
		if (!response.flag ) {
			return false;
		}else{
			chunks = response.chunks;
			ext = response.ext;
			console.log('uploadAccept',response.ext)
			return true
		}
	});
	uploader.on('uploadError', function (file, reason) {
        console.log(reason, 'error')
	});
	uploader.on('uploadSuccess', function (file, reason) {
		console.log('file...',file)
		$.ajax({
            type: 'POST',
            url: '/merge',
            data: {
            	guid,
                chunks,
                ext
            },
            success (data) {
            	const {flag} = data;
            	console.log(flag)
            }
        })
	});
	uploader.on('error', function (type) {
        console.log('error',type);
	});
	uploader.on('uploadComplete', function (file) {
        console.log(file)
	})
</script>
</body>
</html>
const fs = require('fs');
const path = require('path');
const md5  = require('md5');
const express = require('express');
const fileUpload = require('express-fileupload');
const bodyParser = require('body-parser');
const multipart = require('connect-multiparty');
const app = express();
// 生成上传
const uploadFileP = path.resolve(__dirname, `./upload`);
fs.existsSync(uploadFileP) || fs.mkdirSync(uploadFileP);
app.use(bodyParser.urlencoded({ extended: true }));
app.use(fileUpload());
app.use('/assert',  express.static(path.resolve(__dirname, `./assert`)));
app.post('/upload', (req, res) => {
	console.log('/upload...')
	if (!req.files) {
		return res.status(500).send('no files were uploaded');
	}
	let file = req.files.file;
	let body = req.body;
	let {chunk, chunks} = body;
	// 生成文件
	let filePath = path.resolve(__dirname, `./upload/${req.body.guid}`);
	if(!fs.existsSync(filePath)) fs.mkdirSync(filePath);
	file.mv(path.resolve(filePath, `./${chunk}.part`), function(err) {
		let done = true;
		if (err)
			return res.status(500).send(err);
		for (let i = 0 ; i < chunks; i++) {
			if(!fs.existsSync(path.resolve(filePath, `./${i}.part`))) {
				done = false;
				break;
			}
		}
		if (done === true) {
			res.json({flag: true, chunked: true, hasError: false, ext: path.extname(file.name), chunks});
		} else {
			res.json({
				flag: true, chunked: false, hasError: false
			})
		}
	});
});
//合并文件
app.post('/merge', function (req, res) {
	const  body = req.body;
	const {guid, chunks, ext} = body;
	let md = md5(`${guid}${new Date().toString()}${chunks}`);
	let basePath  = path.resolve(__dirname, `./upload/${guid}`);
	let filePh = path.resolve(__dirname, `./upload/${md}${ext}`)
	for (let i = 0; i< chunks; i++) {
		try {
			fs.appendFileSync(filePh, fs.readFileSync(path.resolve(basePath, `./${i}.part`)));
		} catch (e) {
			return req.json({flag: 0})
		}
	}
	return res.json({flag: 1})
	
})
app.listen(3000, () => {
	console.log('sever start..')
});

测试代码

    http://127.0.0.1:3000/assert/index.html