9

webuploader 文件分片上传

为了预研技术大文件分片上传, 找到百度团队维护的webuploader库作为基础。github L6zt
调研策略:

  1. 看看 webupload 前端 如何调用,看看基本demo,接着看看api,结局是貌似文档看着不明白。
  2. 接着看看后端是如何操作,看了看 官方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>

// 效果图
图片描述
项目地址


方糖先生
1.1k 声望1.8k 粉丝