温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Node中怎么利用WebSocket实现多文件下载功能

发布时间:2021-07-21 11:10:47 来源:亿速云 阅读:586 作者:Leah 栏目:web开发

这篇文章将为大家详细讲解有关Node中怎么利用WebSocket实现多文件下载功能,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

列表

Node中怎么利用WebSocket实现多文件下载功能

下载列表

Node中怎么利用WebSocket实现多文件下载功能

本文地址仓库:https://github.com/Rynxiao/yh-tools,如果喜欢,欢迎star.

涉及技术

  • Express 后端服务

  • Webpack 模块化编译工具

  • Nginx 主要做文件gzip压缩(发现Express添加gzip有点问题,才弃坑nginx)

  • Ant-design 前端UI库

  • React + React Router

  • WebSocket 进度回传服务

其中还有点小插曲,最开始是使用docker起了一个nginx服务,但是发现内部转发一直有问题,同时获取宿主主机IP也出现了点问题,然后折磨了好久放弃了。(docker研究不深,敬请谅解^_^)

下载部分细节

Node中怎么利用WebSocket实现多文件下载功能

首先浏览器会连接WebSocket服务器,同时在WebSocket服务器上存在一个所有客户端的Map,浏览器端生成一个uuid作为浏览器客户端id,然后将这个链接作为值存进Map中。

客户端:

// list.jsx await WebSocketClient.connect((event) => {  const data = JSON.parse(event.data);  if (data.event === 'close') {   this.updateCloseStatusOfProgressBar(list, data);  } else {   this.generateProgressBarList(list, data);  } }); // src/utils/websocket.client.js async connect(onmessage, onerror) {  const socket = this.getSocket();  return new Promise((resolve) => {   // ...  }); } getSocket() {  if (!this.socket) {   this.socket = new WebSocket(    `ws://localhost:${CONFIG.PORT}?from=client&id=${clientId}`,    'echo-protocol',   );  }  return this.socket; }

服务端:

// public/javascript/websocket/websocket.server.js connectToServer(httpServer) {  initWsServer(httpServer);  wsServer.on('request', (request) => {   // uri: ws://localhost:8888?from=client&id=xxxx-xxxx-xxxx-xxxx   logger.info('[ws server] request');   const connection = request.accept('echo-protocol', request.origin);   const queryStrings = querystring.parse(request.resource.replace(/(^\/|\?)/g, ''));      // 每有连接连到websocket服务器,就将当前连接保存到map中   setConnectionToMap(connection, queryStrings);   connection.on('message', onMessage);   connection.on('close', (reasonCode, description) => {    logger.info(`[ws server] connection closed ${reasonCode} ${description}`);   });  });  wsServer.on('close', (connection, reason, description) => {   logger.info('[ws server] some connection disconnect.');   logger.info(reason, description);  }); }

然后在浏览器端点击下载的时候,会传递两个主要的字段resourceId(在代码中由parentId和childId组成)和客户端生成的bClientId。这两个id有什么用呢?

每次点击下载,都会在Web服务器中生成一个WebSocket的客户端,那么这个resouceId就是作为在服务器中生成的WebSocket服务器的key值。

bClientId主要是为了区分浏览器的客户端,因为考虑到同时可能会有多个浏览器接入,这样在WebSocket服务器中产生消息的时候,就可以用这个id来区分应该发送给哪个浏览器客户端

客户端:

// list.jsx http.get(  'download',  {   code,   filename,   parent_id: row.id,   child_id: childId,   download_url: url,   client_id: clientId,  }, ); // routes/api.js router.get('/download', async (req, res) => {  const { code, filename } = req.query;  const url = req.query.download_url;  const clientId = req.query.client_id;  const parentId = req.query.parent_id;  const childId = req.query.child_id;  const connectionId = `${parentId}-${childId}`;  const params = {   code,   url,   filename,   parent_id: parentId,   child_id: childId,   client_id: clientId,  };  const flag = await AnnieDownloader.download(connectionId, params);  if (flag) {   await res.json({ code: 200 });  } else {   await res.json({ code: 500, msg: 'download error' });  } }); // public/javascript/annie.js async download(connectionId, params) {   //...  // 当annie下载时,会进行数据监听,这里会用到节流,防止进度回传太快,websocket服务器无法反应  downloadProcess.stdout.on('data', throttle((chunk) => {   try {    if (!chunk) {     isDownloading = false;    }    // 这里主要做的是解析数据,然后发送进度和速度等信息给websocket服务器    getDownloadInfo(chunk, ws, params);   } catch (e) {    downloadSuccess = false;    WsClient.close(params.client_id, connectionId, 'download error');    this.stop(connectionId);    logger.error(`[server annie download] error: ${e}`);   }  }, 500, 300)); }

服务端收到进度以及速度的消息后,回传给客户端,如果进度达到了100%,那么就删除掉存在server中的服务器中起的websocket的客户端,并且发送一个客户端被关闭的通知,通知浏览器已经下载完成。

// public/javascript/websocket/websocket.server.js function onMessage(message) {  const data = JSON.parse(message.utf8Data);  const id = data.client_id;  if (data.event === 'close') {   logger.info('[ws server] close event');   closeConnection(id, data);  } else {   getConnectionAndSendProgressToClient(data, id);  } } function getConnectionAndSendProgressToClient(data, clientId) {  const browserClient = clientsMap.get(clientId);  // logger.info(`[ws server] send ${JSON.stringify(data)} to client ${clientId}`);  if (browserClient) {   const serverClientId = `${data.parent_id}-${data.child_id}`;   const serverClient = clientsMap.get(serverClientId);   // 发送从web服务器中传过来的进度、速度给浏览器   browserClient.send(JSON.stringify(data));   // 如果进度已经达到了100%   if (data.progress >= 100) {    logger.info(`[ws server] file has been download successfully, progress is ${data.progress}`);    logger.info(`[ws server] server client ${serverClientId} ready to disconnect`);    // 从clientsMap将当前的这个由web服务器创建的websocket客户端移除    // 然后关闭当前连接    // 同时发送下载完成的消息给浏览器    clientsMap.delete(serverClientId);    serverClient.send(JSON.stringify({ connectionId: serverClientId, event: 'complete' }));    serverClient.close('download completed');   }  } }

关于Node中怎么利用WebSocket实现多文件下载功能就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI