eggjs 实现视频流上传

在这里插入图片描述

前言

最近公司搞了个大屏,结果客户上传了一个400M的视频,由于网速慢,直接在上传途中给超时了,然后后端用 JAVA 写的个流上传,我想想那我自己也搞个 流上传 , 然后就诞生了这个最最最基础的版本,其他改动后续更新

目录

  1. egg.js 配合 jwt 进行鉴权
  2. egg.js 配置 mysql 以及简单登录实现
  3. eggjs+mysql实现图片上传
  4. eggjs 实现增删改查
  5. eggjs 搭配 vue+axios 实现登录和获取用户信息
  6. eggjs 实现流上传

开发

后端

本章节主要讲解下eggjs怎么通过stream写入视频

修改 app => config => config.default.js

 // 除了upload接口用 mode:'file' , 其他都用 `stream`
  config.multipart = {
    mode: 'stream',
    fileModeMatch: /(\/upload)$/,
    fileSize: 1048576000,
    whitelist: [".txt", ".png", ".jpg",'.mp4'],
  };

修改 app => controller => upload.js 加入

  async uploadStream() {
    const stream = await this.ctx.getFileStream();
    const {
      filename,
      fields: { chunk, chunks },
    } = stream;
    const day = moment(new Date()).format("YYYYMMDD");
    const dir = path.join(this.config.uploadDir, day);
    let buf;
    let uploadDir = "";
    try {
      await mkdirp(dir); // 不存在就创建目录
      uploadDir = path.join(dir, filename);
      const streams = fs.createWriteStream(uploadDir, {
        flags: "a",
      });
      const parts = await toArray(stream);
      buf = Buffer.concat(parts);
      streams.write(buf);
      // 当 chunk === chunks , 证明已经文件已经上传完毕 , 可以直接写入数据库
      if (chunk === chunks) {
        console.log("上传数据库");
      }
    } catch (e) {
      await sendToWormhole(stream);
      ctx.cleanupRequestFiles();
      throw e;
    }
    this.ctx.body = {
      code: 200,
      msg: "上传成功",
      data: uploadDir.replace(/app/g, ""),
    };
  }
}

修改 app => router.js , 加入

 router.post('/uploadStream',_jwt, controller.upload.uploadStream);

接下来我们通过ajax写一个接口请求

前端

<!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>
    <input type="file" id="file" />

    <button id="upload">上传</button>

    <script src="../js/jquery.js"></script>
    <script>
      $('#upload').on('click', function (params) {
        let file = $('#file').prop('files')[0];
        let uid = new Date().getTime();
        let sliceSize = 10 * 1024 * 1024;
        let blob = file;
        const fileSize = file.size; // 文件大小
        const fileName = file.name; // 文件名
        const totalSlice = Math.ceil(fileSize / sliceSize);
        const pormiseArr = [];
        for (let i = 1; i <= totalSlice; i++) {
          let chunk;
          if (i == totalSlice) {
            chunk = file.slice((i - 1) * sliceSize, fileSize); //切割文件
          } else {
            chunk = file.slice((i - 1) * sliceSize, i * sliceSize);
          }
          const formData = new FormData();
          formData.append('size', fileSize);
          formData.append('chunks', totalSlice);
          formData.append('chunk', i);
          formData.append('name', uid + fileName);
          formData.append('file', chunk, uid + fileName);
          pormiseArr.push(formData);
        }
        callback(pormiseArr, 0);
      });
      // 这里之所以采用回调,是因为如果全部通过同步的,可能会出现后端拼接报错的可能
      // 这里回调其实并没有解决上传较慢的问题,但是在一定层度解决了上传太久出现超时的问题
      function callback(arr, index) {
        $.ajax({
          url: 'http://localhost:7001/uploadStream',
          type: 'POST',
          data: arr[index],
          processData: false, // 不处理数据
          contentType: false, // 不设置内容类型
          success: function () {
            if (index != arr.length - 1) {
              callback(arr, index + 1);
            } else {
              console.log('上传成功');
            }
          },
        });
      }
    </script>
  </body>
</html>

结果

在这里插入图片描述

改进

  1. 如上诉说的,因为服务器并没有通过多线程等上传,导致服务器在前端进行上传时可能导致服务器拼接流的时候出现错乱…,这个问题我是用前端解决,通过一个上传后再上传另一个来解决这个问题,但是这个问题并不能缓解上传慢的问题(上传快可以,加宽带价钱==),但是解决了上传后超时的问题
  2. 我们通过 chunkchunks 可以判断上传进度,所以 (1)前端可以写个进度条方便用户更直观看到上传进度(2)后端可以通过这两个字段来实现断点续传的功能,也就是不断通过记录 chunk 来记录进度的 位置 (tips: 这可能是个不太成熟的想法)
  3. 播放流的问题最近也在 着手 ,其实 video标签就可以实现了,如果有 token 需求可以用 xgplayer,也不失为一种解决方法
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Django是一个基于Python的web框架,主要用于快速开发网站。虽然Django本身并不提供直接的视频媒体功能,但是我们可以借助第三方库和技术来实现。 要实现视频媒体,首先需要一个用于存储和提供视频文件的服务器。可以选择使用类似Nginx或Apache等web服务器来提供视频文件,或者使用一些专门的存储服务如AWS S3等。 在Django中,我们可以使用django-video-encoding库来处理视频文件的编码和转换。该库提供了一些函数和类,可以用于将视频文件转换为不同的格式和编码,以便在各种浏览器和设备上进行播放。 为了在网站上实现视频媒体,我们需要使用HTML5的video标签。在Django的模板中,可以使用该标签来嵌入视频,如下所示: ```html <video controls> <source src="{{ video_url }}" type="video/mp4"> Your browser does not support the video tag. </video> ``` 其中,`{{ video_url }}`是一个变量,用于指定视频文件的URL地址。这个变量可以在Django的视图函数中通过查询数据库或其他途径获取视频文件的URL。 当用户访问包含视频媒体的页面时,Django会根据URL和视图函数,将视频文件的URL递给模板,然后在浏览器中渲染出视频播放器。用户可以通过播放器来播放和控制视频的播放。 需要注意的是,视频媒体对于服务器的负载是比较大的,因此在实现视频媒体时,需要考虑服务器的性能和带宽等因素。同时,也可以通过使用CDN等技术,将视频文件缓存到全球各地的服务器上,降低服务器的负载和提高视频播放的效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值