大文件上传

213 阅读2分钟

大文件上传,参考地址demo:gitee.com/chenganglon…

1.认识大文件上传(是什么?)

大文件一般是指占用内存空间比较大的文件,比如我们下载的小电影,MV,4k的高清图片等等,一般把100MB以上的文件称为大文件

2.为什么要做大文件上传(为什么?)

如果一个文件有足够大的时候,用户等待的时间可能还做各种的操作,比如等待,取消下载,甚至关闭整个浏览器,这些操作都影响我们的存储,我到底是把用户上传的东西存下来呢还是不存呢,这个就没有一个明确的规定了

3.怎么做大文件上传(怎么做?)

1.大文件上传主要是对某个文件的空间进行slice()的切割,我们称为切片上传

前端:

1.点击上传的时候,首先要判断,file中有没有放东西上去,其次要判断上传文件的类型
2.做上传逻辑,就是把在 const file = videoUploader.files[0]中的file的 name size type丢给后端
3.切片上传
while(uploadSize < size){ 
    const fileChunk = file.slice(uploadSize, uploadSize + CHUNK_SIZE);
}
循环请求,在本地保留文件的大小 与 本文件的大小进行比较
const BASEURL = 'http://localhost:8000/';

export const UPLOAD_INFO = {
    'NO_files':'请选择文件上传',
    'FileTypeError':'不支持类型上传',
    'FileTypeSuccess':'上传成功',
    'upload_Error':'上传失败'
}

export const ALLOW_TYPE = {
    "image/png":'png',
    "video/mp4":'mp4'
}

// 64K
export const CHUNK_SIZE = 64 * 1024

// API路径

export const API ={
    URL:BASEURL + 'upload_video'
}
import {UPLOAD_INFO, ALLOW_TYPE, CHUNK_SIZE,API} from './config'
import axios from 'axios'

;((doc)=>{

    const uploadProgress = doc.querySelector('#uploadProgress');
    const videoUploader = doc.querySelector('#videoUploader');
    const uploadInfo = doc.querySelector('#uploadInfo');
    const uploadBtn = doc.querySelector('#uploadBtn');
    
    // 保留上传的大小
    let uploadSize = 0;

    const init = () => {
        bindEvent();
    }   

    function bindEvent() {
        uploadBtn.addEventListener('click',uploadVideo,false);
    }

    async function uploadVideo() {
        const file = videoUploader.files[0];
        //  file没上传为undefined
        if(!file){
            uploadInfo.innerText = UPLOAD_INFO['NO_files'];
            return;
        }
        // 判断上传文件的类型
        if( !ALLOW_TYPE[file.type] ){
            uploadInfo.innerText = UPLOAD_INFO['FileTypeError']
        }else{
            uploadInfo.innerText = UPLOAD_INFO['FileTypeSuccess'] + 1
        }
        // 上传逻辑 name size type
        const { name, size ,type } = file
        const fileName = new Date().getTime() + name
        uploadProgress.max = size
        while(uploadSize < size){
            const fileChunk = file.slice(uploadSize, uploadSize + CHUNK_SIZE);
            const formData = createFormData({name, size ,type,fileName,uploadSize,file:fileChunk})
            // 发请求到后端
            try{
                const res =  await axios.post(API.URL,formData)
                console.log(res.data.data)
            } catch(e){
                uploadInfo.innerText = `${UPLOAD_INFO['upload_Error']}(${e})`
                return
            }
            uploadSize += fileChunk.size
            uploadProgress.value = uploadSize
        }
        uploadInfo.innerText = UPLOAD_INFO['FileTypeSuccess'] + 2
        videoUploader.value = null
    }
    function createFormData( {name, size ,type,fileName,uploadSize,file} ){
        const fd = new FormData()
        fd.append('name' , name);
        fd.append('size' , size);
        fd.append('type' , type);
        fd.append('fileName' , fileName);
        fd.append('uploadSize' , uploadSize);
        fd.append('file' , file);
        return fd
    }
    init();

})(document);

后端:

const express = require('express')
const bodyParser = require('body-parser')
const upload = require('express-fileupload')
// 获取后缀
const { extname,resolve } = require('path')
const { existsSync,appendFileSync,writeFileSync } = require('fs')

const app = express()

app.use(bodyParser.urlencoded({ extended:true }))
app.use(bodyParser.json())
app.use(upload())
app.use('/',express.static('upload'))

// 处理跨域
app.all('*',(req, res, next)=>{
    res.header('Access-Control-Allow-origin','*');
    res.header('Access-Control-Allow-Methods','POST,GET');
    next()
})

const ALLOW_TYPE = {
    "image/png":'png',
    "video/mp4":'mp4'
}

app.post('/upload_video',(req, res)=>{
    // 接受到前端的少了file
    // const { name, size ,type,fileName,uploadSize } = req.body
    // // 获取file
    // const { file } = req.files
    // if( !file ){
    //     res.send({
    //         code:1001,
    //         msg:'未上传文件'
    //     })
    //     return
    // }

    // // 判断类型(安全)
    // if( !ALLOW_TYPE[type] ){
    //     res.send({
    //         code:1002,
    //         msg:'文件类型不支持'
    //     })
    //     return 
    // }
    // // 文件名
    // const filename = fileName + extname(name);
    // // 获取文件夹路径
    // const filePath = resolve(__dirname,'./upload/' + filename )
    // if( uploadSize !== '0' ) {
    //     if( !existsSync(filePath) ){
    //         res.send({
    //             code:1003,
    //             msg:'文件类型不存在'
    //         })
    //         return
    //     }
    //     appendFileSync( filePath,file.data )
    //     res.send({
    //         code:0,
    //         msg:'Appended',
    //         data:{
    //             video_url:'http://localhost:8000/' + filename
    //         }
    //     })  
    //     return
    // }
    // // 文件存在
    // writeFileSync(filePath,file.data)
    // res.send({
    //     code:0,
    //     msg:'File is created'
    // })  

})

const PORT = 8000

app.listen(PORT ,() => {
    console.log( 'server in the http://localhost:8000/upload_video' )
})