大文件切片上传---node+js

// 简单的页面布局
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div>
    <p>
      <progress id="uploadProgress" value="0"></progress>
    </p>
    <p>
      <input type="file" id="videoUploader" value="选择视频" />
    </p>
    <p>
      <span id="uploadInfo"></span>
    </p>
    <p>
      <button id="uploadBtn">上传视频</button>
    </p>
  </div>
  <video></video>
</body>
<script src="./app.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

</html>

// 大文件切片上传---js逻辑
// 设置地址
const BASE_URL = 'http://localhost:8080/';
// 定义一些提示信息
const UPLOAD_INFO = {
  'NO_FILE': '请选择文件',
  'INVALID_TYPE': '上传文件的格式不对',
  'UPLOAD_FAILED': '上传失败',
  'UPLOAD_SUCCESS': '上传成功'
};
// 定义符合的格式
const ALLOWED_TYPE = {
  'video/mp4': 'mp4',
  'video/ogg': 'ogg'
};
// 设置要切割文件的大小
const CHUNK_SIZE = 64 * 1024;
// 设置axios的接口
const API = {
  UPLOAD_VIDEO: BASE_URL + 'upload_video'
}
  ; ((doc) => {
    // 获取进度条
    const oProgress = doc.querySelector('#uploadProgress');
    // 获取上视频
    const oUpLoader = doc.querySelector('#videoUploader');
    // 获取提交信息标签
    const oInfo = doc.querySelector('#uploadInfo');
    // 获取提交button
    const oBtn = doc.querySelector('#uploadBtn');
    // 定义上传的初始值
    let uploadedSize = 0;
    // 初始化操作
    const init = () => {
      //调用绑定提交事件函数
      bindEvent();
    };
    // 绑定提交事件
    function bindEvent() {
      oBtn.addEventListener('click', uploadVideo, false);
    };
    // 处理文件的函数
    async function uploadVideo() {
      // 获取上传的视频的一些信息
      const { files: [file] } = oUpLoader;
      // 判断是否上传文件
      if (!file) {
        // 提示
        oInfo.innerText = UPLOAD_INFO['NO_FILE'];
        return;
      };
      // 判断上传的文件格式是否符合要求(file里面有一个type属性是查看上传视频的格式)
      if (!ALLOWED_TYPE[file.type]) {
        // 提示
        oInfo.innerText = UPLOAD_INFO['INVALID_TYPE'];
        return;
      };
      // 从file中提取出name type size
      const { name, type, size } = file;
      // 设置一个fileName 这样写只是为了测试 开发中不建议
      const fileName = new Date().getTime() + '-' + name;
      // 声明一个用来接受请求的结果
      let uploadedResult = null;
      // 给进度条设置最大值
      oProgress.max = size;
      // 清空提示信息里面的内容
      oInfo.innerText = '';
      //循环切割 如果小于文件大小就一直切割
      while (uploadedSize < size) {

        // 开始切割
        const fileChunk = file.slice(uploadedSize, uploadedSize + CHUNK_SIZE);
        // 调用函数且传参
        const formData = createFormData({
          name,
          type,
          size,
          fileName,
          uploadedSize,
          file: fileChunk
        });
        // 发送上传请求
        try {
          uploadedResult = await axios.post(API['UPLOAD_VIDEO'], formData);
        } catch (error) {
          oInfo.innerText = UPLOAD_INFO['UPLOAD_FAILED'] + error.message;
          return;
        }
        // 给上传大小重新赋值
        uploadedSize += fileChunk.size;
        // 进度条等于上传大小
        oProgress.value = uploadedSize;
      };
      // 最后提示上传成功
      oInfo.innerText = UPLOAD_INFO['UPLOAD_SUCCESS'];
      // 清空数据
      oUpLoader.value = null;
      // 创建视图
      createVideo(uploadedResult.data.video_url);
      // debugger
      return;
    };
    // 创建函数分装需要上传的东西
    function createFormData({
      name,
      type,
      size,
      fileName,
      uploadedSize,
      file
    }) {
      // 创建formData
      const fd = new FormData();
      fd.append('name', name);
      fd.append('type', type);
      fd.append('size', size);
      fd.append('fileName', fileName);
      fd.append('uploadedSize', uploadedSize);
      fd.append('file', file);
      return fd;
    }
    function createVideo(src) {
      const oVideo = document.createElement('video');
      oVideo.controls = true;
      oVideo.width = '500';
      oVideo.src = src;
      document.body.appendChild(oVideo);
      // debugger
    }
    //调用初始化
    init();
  })(document);


// 大文件上传---node.js (1.npm init --yes  2.npm i express 3.创建upload_temp 保存传过来的视频)
const express = require('express');
const app = express();
// 处理文件
const uploader = require('express-fileupload');
// 解析body
var bodyParser = require('body-parser');
// 帮助我们转化类型的
const { extname, resolve } = require('path');
// 帮助我们写文件 追加文件 和 编文件
const { existsSync, appendFileSync, writeFileSync } = require('fs');
// 使用
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// 使用
app.use(uploader());
// 设置访问静态文件
app.use('/', express.static('upload_temp'));
const ALLOWED_TYPE = {
  'video/mp4': 'mp4',
  'video/ogg': 'ogg'
}
// 设置容许跨域
app.all('*', (req, res, next) => {
  res.header('Access-Control-Allow-origin', '*');
  res.header('Access-Control-Allow-Methods', 'POST,GET');
  next();
});
// 配置接口
app.post('/upload_video', (req, res) => {
  // 从req.body里面结构出以下
  const {
    name,
    type,
    size,
    fileName,
    uploadedSize
  } = req.body;
  // 从files里面结构出file
  const { file } = req.files
  // 判断里面是否有file属性
  if (!file) {
    res.send({
      code: 1001,
      msg: 'No file uploaded'
    });
    return;
  };
  // 判断是否符合上传的类型
  if (!ALLOWED_TYPE[type]) {
    res.send({
      code: 1002,
      msg: 'The type not allowed for uploading.'
    });
    return;
  };
  // 转化类型 利用path里面的extname方法进行拼接转化 
  const filename = fileName + extname(name);
  const filePath = resolve(__dirname, './upload_temp/' + filename)
  // 判断uploadeSize是否等于0 
  if (uploadedSize !== '0') {
    if (!existsSync(filePath)) {
      res.send({
        code: 1003,
        msg: 'No file exists'
      });
      return;
    }
    // 追加file.data
    appendFileSync(filePath, file.data);
    res.send({
      code: 0,
      msg: 'Appended',
      video_url: 'http://localhost:8080/' + filename
    });
    return;
  };
  // 如果以上条件都没有符合的话 我们就写入
  writeFileSync(filePath, file.data);
  // 发送写完
  res.send({
    code: 0,
    msg: 'File is created'
  });
});
// 配置端口号
const POST = 8080;
// 启动
app.listen(POST, () => {
  console.log('服务已经启动...');
});

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值