webuploader 文件分片上传
为了预研技术大文件分片上传, 找到百度团队维护的webuploader库作为基础。github L6zt
调研策略:
- 看看 webupload 前端 如何调用,看看基本demo,接着看看api,结局是貌似文档看着不明白。
- 接着看看后端是如何操作,看了看 官方GitHub 里的server 目录,看看对应的后端处理。里面的PHP 也看的不太清晰。
不知道是文档写的差,还是我理解差,或者自己没看全。总之是不太清晰的,但是比我司写的wiki要好多了??
接着就是一顿蒙搞,同时借鉴前人的东西... 后端自己用 node(epxress)写了简单的上传接口。前端 照着demo搞了搞结果就成功了。 只是demo里面有其他问题。
// node 服务器 只是为了做测试
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) => {
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) {
// chunked 这个参数 貌似很重要
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..‘)
});
// 前端资源
<!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 * 100,
chunkRetry: 3,
thread: 5,
formData: {
guid,
}
});
// 貌似检查分片上传 是不是 对的
uploader.on( ‘uploadAccept‘, function( file, response ) {
// resopnse 后端返回数据
if (!response.flag ) {
return false;
}else{
chunks = response.chunks;
ext = response.ext;
return true
}
});
uploader.on(‘uploadError‘, function (file, reason) {
console.log(reason, ‘error‘)
});
// 分片上传(all)成功后 调用合并接口
uploader.on(‘uploadSuccess‘, function (file, reason) {
$.ajax({
type: ‘POST‘,
url: ‘/merge‘,
data: {
guid,
chunks,
ext
},
success (data) {
const {flag} = data;
console.log(flag)
}
})
});
uploader.on(‘error‘, function (type) {
console.log(type);
});
uploader.on(‘uploadComplete‘, function (file) {
console.log(file)
})
</script>
</body>
</html>
// 效果图
项目地址