首页 > 其他分享 >前端大文件上传如何做到刷新续传?

前端大文件上传如何做到刷新续传?

时间:2023-11-17 12:32:13浏览次数:31  
标签:const socket userId io 刷新 console 上传 续传

前言

这两天在学习阿里云oss上传。踩了不少坑,终于实现了大文件分片、断点续传的功能。这篇文章主要分享学习笔记,希望能给大家一些帮助。先看效果

前端大文件上传如何做到刷新续传?_客户端

 

技术栈

1.前端: react+Ts + axios 上传文件

2.Node部分:定义接口、阿里云 oss

3.socket.io :实时同步上传进度 特别说明 axios 中 onUploadProgress 只是上传本地文件的进度,不是上传服务器存入的进度,需要socket.io 从服务端实时返回上传进度

环境安装

需进行阿里云oss配置,获取appid、密钥等参数 ↓阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台 以下是创建node服务所需依赖包

// 下载 Koa 模块
npm install koa
// 下载 Koa Router 模块 https://www.npmjs.com/package/koa-Router[包含示例代码]
npm install koa-router
// 下载 @koa/cors 模块
npm install @koa/cors
// 下载 ali-oss 模块
npm install ali-oss
// 下载 koa-body 模块
npm install koa-body
// 下载 socket.io
npm install socket.io
前端部分

前端使用react+Ts,但无论哪种框架,其实业务逻辑是一样的

初始化socket

let userId = localStorage.getItem('userId');
            if (!userId) {
                userId = new Date().getTime() + '';
                localStorage.setItem('userId', userId);
            }   
               let host = 'http://127.0.0.1:3000'                const soket = io(host); 
                soket.on('connect', function(){
                    console.log('链接了 Connected to server');  
                 }); 
        // 模拟用户登录
                 soket.emit('login',{
                    userId
                })                soket.on('success', data => {
                    console.log('success',data)
                })文件上传
const upload = async () => {
  // FileList 内置接口
  const file = (inputRef.current?.files as FileList)[0];
  console.log('inputRef', file);
  if (!file) {
    message.error('没有选择文件');
    return;
  }
  let formData = new FormData();
  formData.append('file', file);
  let userId = localStorage.getItem('userId') as string
  formData.append('userId',userId)
  await axios.post(host+'/upload', formData, {
    // onUploadProgress 监听的是客户端发送数据的进度,而不是存储服务器的进度。
    onUploadProgress: (progressEvent: any) => {
      const percentage = Math.round((progressEvent.loaded * 100) / progressEvent.total);
      console.log(`Upload progress: ${percentage}%`, progressEvent);
    }
  });
};

 

进度回显
const [progress,setProgress] = useState<number>(0)
soket.on('uploadding', data => {
         console.log('uploadding',data)
        setProgress(data)
  })node部分
后台使用koa创建node服务,主要分为api接口、阿里云业务函数、socket.io 实时发送上传进度
socket.io
const { createServer } = require("http"); // 导出创建服务的模块函数
const { Server } = require("socket.io"); // 创建socket.io 服务的函数
const httpServer = createServer(app.callback());  // 创建一个http服务实例,app.callback() 作为服务器的请求处理函数
const io = new Server(httpServer, {
    cors: {
        origin: "*" // 配置socket允许跨越
    }
});
上传接口// 上传接口
router.post('/upload', async (ctx, next) => {
    let file = ctx.request.files.file;
    // 用户id 
    let userId = ctx.request.body.userId
    try {
        let result = null;
        await next();
        // 判断文件大小,超过partSize进行分片上传
        if (file.size < partSize) {
            console.log('直连操作');
            result = await commonUpload(file, userId);
        } else {
            console.log('分片上传');
            result = await multipartUpload(file, userId);
        }
        ctx.body = {
            code: 200,
            message: 'success',
            data: result
        };
    } catch (error) {
        console.log('error', error);
        ctx.body = {
            message: '上传失败',
            code: 401
        };
    }
});暂停接口
router.post('/break', async (ctx) => {
    let userId = ctx.request.body.userId
    // 取出 当前用户的阿里云实例,用于仅关闭当前上传
    let itemClient = userList[userId]['client']
    if (itemClient) {
        itemClient.cancel();
        ctx.body = {
            code: 200,
            message: "暂停成功"
        }
    } else {
        ctx.body = {
            code: 401,
            message: "暂停失败"
        }
    }});
继续上传接口
// 继续上传 
router.post('/continue', async (ctx) => {
    let userId = ctx.request.body.userId
    ctx.body = {
        code: 200,
        message: '已继续上传',    };
    try {
        resumeMultiparUpload(userId)
    } catch (error) {
        console.log('继续上传报错')
    }});
分片上传
// 分片上传
const multipartUpload = async (file, userId) => {    try {
        let result = await userList[userId].client.multipartUpload(file.originalFilename, file.filepath, {
            parallel,
            partSize,
            progress: (p, checkpoint) => {
                onProgress(p, checkpoint, userId)
            }
        });
        return result;
    } catch (error) {
        console.log('multipartUpload', error)
    }
};断点续传
// 断点续传
const resumeMultiparUpload = async (userId) => {
    // 获取当前用户分片缓存 
    try {
        let checkpoint = checkpoints[userId]
        const { uploadId, file } = checkpoint;
        let result = await userList[userId].client.multipartUpload(uploadId, file, {
            parallel,// 分片数量
            partSize,//分片大小
            progress: (p, checkpoint) => {
                onProgress(p, checkpoint, userId)
            },// 上传进度回调函数
            checkpoint // 断点续传缓存目录
        });
        //上传后,删除切片数据
        delete checkpoints[userId]
        console.log('result', result)
        return result;
    } catch (error) {
        console.log('error 获取当前用户分片缓存')
    }}
进度回显
// 上传进度
const onProgress = async (p, checkpoint, userId) => { // p 进度,checkpoint 当前分片上传数据
    let step = Math.floor(p * 100); // 转换为百分比
    io.to(userList[userId].socketId).emit('uploadding', step) // 发给当前客户端
    // io.emit('uploadding',step) 群发
    // 存储分片数据,用户续传
    console.log('上传进度', step)
    checkpoints[userId] = checkpoint
};socket.io私聊
const userList = {}  // 用户数据
const partSize = 1024 * 100; // 每个分片大小(byte) 100kb
const parallel = 3; // 同时上传的分片数
let checkpoints = {}; // 记录上传分片数据,用于断点续传
// oss客户端实例   // socket.io系统事件,监听链接状态
io.on("connection", (socket) => {
    // 监听客户端信息数据,存储用户信息    socket.on('login', (data) => { 
        // 用户未链接oss,进行创建oss实例
        if (!userList[data.userId]) {            let client = new OSS({
                // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
                region: 'oss-cn-beijing',
                // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控W制台创建RAM用户。
                accessKeyId: 'xxx',
                accessKeySecret: 'xx',
                bucket: 'xxx
            });            // 将socket.id 与用户信息关联存储,方便私聊发送
            userList[data.userId] = {
                ...data,
                socketId: socket.id,
                client: client
            }
            console.log('socket.id', socket.id)
            console.log('获取到用户数据')
        } else { // 已链接oss,进行只更新socket.id
            userList[data.userId].socketId = socket.id
        }
    })
    socket.emit('success', '服务端链接成功了')
    // socket.io 系统事件-客户端断开监听
    socket.on('disconnect', () => {
        console.log('客户端断开了')
        // io.emit('quit', socket.id)
    })
});
纯前端操作部分如无服务端业务要求,建议客户端调用阿里云sdk,实现上传oss功能,操作如node一致,阿里云sdk同样支持分片上传等,最方便的是无需再创建socket获取进度。 兄弟们,点赞收藏过20,下篇文章更新呀Socket 相关api
在Socket.IO 中,客户端和服务端都有一些系统事件。
服务端系统事件:
connection:当客户端与服务器建立连接时触发。可以在此事件中执行与连接相关的操作。
io.on("connection", (socket) => {
  // 处理连接事件
});
disconnect:当客户端与服务器断开连接时触发。可以在此事件中执行与断开连接相关的操作。socket.on("disconnect", () => {
  // 处理断开连接事件
});
error:当在连接过程中发生错误时触发。可以在此事件中处理连接错误。socket.on("error", (err) => {
  // 处理连接错误事件
});
to 在 Socket.IO 中,to 方法用于向特定房间或客户端发送消息。它允许你将消息发送给指定的接收者。to 方法的使用方法如下:io.on('connection', (socket) => {
  // 建议 将socket.id 与用户信息关联存储,方便私聊发送
  // 向指定客户端发送消息
  io.to(socket.id).emit('message', 'Hello from server!');
});
使用 io.to(socket.id).emit('message', 'Hello from server!') 向特定客户端发送消息,其中 socket.id 表示当前客户端的唯一标识符。

客户端系统事件:

connect:当客户端成功连接到服务器时触发。该事件仅发生在客户端连接成功时。

socket.on("connect", () => {
  // 处理连接成功事件
});
disconnect:当客户端与服务器断开连接时触发。可以在此事件中执行与断开连接相关的操作。socket.on("disconnect", () => {
  // 处理断开连接事件
});
error:当在连接过程中发生错误时触发。可以在此事件中处理连接错误。socket.on("error", (err) => {
  // 处理连接错误事件
});
注意socket 开启跨越 :::warning http://socket.io 需配置跨越,否则无法链接,参考 https://socket.io/zh-CN/docs/v4/handling-cors/ :::const io = new Server(httpServer, {
  cors: {
    origin: "http://localhost:8080" // 前端访问地址 、"*" 允许所有跨越
  }
});httpServer.listen(3000);
koa+socket使用事项 :::warning 接口后台和socket端口一致情况下,需使用包含socket的服务实例来创建监听,否则socket无法链接 ::: 在koa中使用socket.io 需要创建一个包含socket.io的服务实例,代码示例如下:const app = new (require("koa"))();
const router = require("koa-Router")();
const { createServer } = require("http");
const { koaBody } = require("koa-body");
const {Server} = require('socket.io')
app.use(cors()); // 允许接口跨域
app.use(router.routes());
// 创建socket服务  
const httpServer = createServer(app.callback());
const io = new Server(httpServer,{
    cors:{
        origin:"*" // 允许socket跨域
    }
}) 
io.on('connection', () => { 
  console.log('服务链接了')
  /* … */ });  
// 使用包含socket的服务示例,如果使用koa中的app实例,则无法监听socket服务
httpServer.listen(9000, () => {
  console.log("koa server listening on port 9000");
});

 

参考文章:http://blog.ncmem.com/wordpress/2023/10/11/前端大文件上传如何做到刷新续传?/


 

标签:const,socket,userId,io,刷新,console,上传,续传
From: https://blog.51cto.com/u_14023400/8439859

相关文章

  • java如何做大体积的文件上传和下载
    在Java中,实现大体积文件的上传和下载涉及到处理文件的分片、并发上传、断点续传等问题。本文将详细介绍如何通过Java实现大体积文件的上传和下载。1.文件上传文件上传是将本地文件上传到服务器的过程。对于大体积文件的上传,我们可以将文件分成多个小片段进行并发上传。1.1文件分......
  • 前端如何实现大文件上传
    在开发过程中,经常会遇到一些较大文件上传,如果只使用一次请求去上传文件,一旦这次请求中出现什么问题,那么无论这次上传了多少文件,都会失去效果,用户则需要重新上传所有资源。所以就想到一种方式,将一个大文件分成多个小文件,这样通过多个请求实现大文件上传。接下来我们就来看看具体是怎......
  • HTML5中怎么实现文件断点续传功能
    HTML5中怎么实现文件断点续传功能,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。断点续传原理目前比较常用的断点续传的方法有两种,一种是通过websocket接口进行文件上传,另一种是通过ajax,两种方法各有千秋......
  • 大文件断点续传上传
    最近接到一个新的需求,需要上传2G左右的视频文件,用测试环境的OSS试了一下,上传需要十几分钟,再考虑到公司的资源问题,果断放弃该方案。一提到大文件上传,我最先想到的就是各种网盘了,现在大家都喜欢将自己收藏的「小电影」上传到网盘进行保存。网盘一般都支持断点续传和文件秒传功能,减少......
  • 通过Java实现文件断点续传功能
    用户上传大文件,网络差点的需要历时数小时,万一线路中断,不具备断点续传的服务器就只能从头重传,而断点续传就是,允许用户从上传断线的地方继续传送,这样大大减少了用户的烦恼。本文将用Java语言实现断点续传,需要的可以参考一下什么是断点续传用户上传大文件,网络差点的需要历时数小时,万......
  • webuploader实现大文件断点续传
    前端代码(基于Yii框架,逻辑可供参考)   <script>    varfileMd5; //文件MD5    varfileObj; //文件对象    varstate='pending'; //状态    WebUploader.Uploader.register({      "before-send":"beforeSend......
  • linux下使用命令行工具alidrive上传文件到阿里云盘
    linux下使用命令行工具alidrive上传文件到阿里云盘下载alidrive,并解压wgethttps://github.com/aoaostar/alidrive-uploader/releases/download/v2.2.1/alidrive_uploader_v2.2.1_linux_amd64.tar.gztar-xvfalidrive_uploader_v2.2.1_linux_amd64.tar.gz修改配置文件重......
  • springboot整合前端实现断点续传、大文件秒传以及多线程上传下载
    前端,百度开源框架webuploader新建upload.htmlwebuploader官网地址:http://fex.baidu.com/webuploader/<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>webuploader</title></head><!--引......
  • SpringBoot 中大文件(分片上传)断点续传与极速秒传功能的实现
    1.背景在实际项目中,我们经常会遇到需要上传大文件的情况,常见的方法是将整个文件一次性上传,在文件较大时会出现上传速度慢或者可能导致上传失败等问题。针对这种情况,通常可以采用分片上传的方式,将文件分为多个小片段进行上传,降低单个上传请求的负载,提高上传效率。同时,考虑到用户......
  • 如何通过 wireshark 捕获 C# 上传的图片
    一:背景1.讲故事这些天计划好好研究下tcp/ip,以及socket套接字,毕竟工控中设计到各种交互协议,如果只是模模糊糊的了解,对分析此类dump还是非常不利的,而研究协议最好的入手点就是用抓包工具wireshark,废话不多说,这篇通过wireshark提取一个小图片作为入手。二:wireshark图片抓包1......