一、 项目简述
我们做的是一套聊天软件, 目前的文件传输是无法取消发送的, 用户很有可能发了不该发的文件给别人, 却又无法取消, 只能默默等待上传结束的一瞬间选择撤回消息, 那需求就来了.
(来自产品经理)“ 聊天模块中传输文件显示传输进度条,需要支持取消, 并且能够点击重新发送该文件”
二、项目结构
我们的聊天数据是采用better-sqlite3建立本地数据库,实现的消息存储,建立多张表(比如chat, message,user等), 发送文件是先生成一个local文件id, 通过axios post文件片段到文件服务器进行传输.
因此该需求要实现的变更显而易见:
- 想办法获取axios的上传进度, 并且记录下数据, 便于vue开发的组件可以获取该进度, 进行渲染.
- 由于存在传送多个文件的post请求, 因此需要在每个文件对应的post请求过程pending状态中, 能够取消对应文件的上传.
三、 确定方案
针对(二)中描述的问题, 通过查阅Axios官网API, 很快就敲定了解决策略
-
利用axios的请求配置中的 -> onUploadProgress 处理原生进度事件.
(详情可以参考Axios官网 https://axios-http.com/zh/docs/req_config) -
取消文件的方式根据文档(https://axios-http.com/zh/docs/cancellation),有两种方案, 一是采用以 fetch API 方式取消请求(AbortController), 二是通过Axios的 cancel token. 其实更推荐用第一种方案, 不过要求是axios版本最低为0.22.0, 由于我们的项目即将重构, 老版本就还是暂用以前的0.19版本, 因此选择了CancelToken方案.
四、 实战部分
介绍完需求和方案确立过程, 开始尝试在项目中使用.
(1) 文件传输进度条显示部分
1.针对数据库的操作
在ChatFile表中增加extra_param字段,存储上传过程中的进度数据.
在Message表中关联对应msg_id对应Chat, 通过chat_id关联chatFile的进度, 存储在file_upload_progress中, 在实际聊天中用于显示, 具体细节不做描述, 涉及业务架构.与本文无关.
2.在Axios请求配置中增加onUploadProgress用于记录当前的上传进度数据:
...
await uploadFile (param, {
onUploadProgress: (progress) => {
const uploadProgress = ((progress.loaded / progress.total) * 100) | 0;
chatFile.extra_param = String(uploadProgress);
ChatFileTable.updateChatFileById(db, localFileId, chatFile);
updateStoreWithChatIdMsgId(store, chatFile.chat_id, chatFile.msg_id);
}, // 这一步将该文件存入Message表中, 在组件中已经是可读取状态
},
}).then(...
...
- 在组件中读取进度,用于显示:(业务代码已省略)
<template>
...
<div v