业务需求中出现一个接口既有导入功能,又需要有导出功能,接口具体情况如下:

导入excel表格接口中,前端传递上传的excel文档,后端判断文档是否格式正常,如果格式正常,则返回json格式的成功数据,如果格式不成功,则返回错误的excel文档,前端负责把错误的excel文档导出,第三种情况,如果5s内再次导入文档,则后端返回不能频繁导入的错误json数据。

总结一下:

情况1:前端导入excel表格,触发请求,后端响应文件,blob格式,导入数据失败,前端导出文件;

情况2:前端导入excel表格,触发请求,后端响应json格式,导入数据正常,存储到数据库中;

情况3:前端5s内再次导入excel表格,触发请求,后端响应json格式,导入数据失败,不能频繁导入;

情况1:导出excel由于格式问题打不开

导出接口处理如下:

const apiImportExcel = (params) => {return axiosBizcenterMarketingAct.request({url: 'https//www.xxx.com/importExcelOptLessNum',method: 'post',data: params})
}// 上传excel,失败下载excel,成功返回msg
const uploading = async (data) => {uploadLoading.value = truelet file = data.filelet params = new FormData()params.append('file', file)let res = await apiImportExcel(params)console.log(res, 1234)blobData.value = resisShowDownload.value = trueuploadMessage.value = '处理失败,请整理表格后重新上传文档'uploadLoading.value = falsedialogVisible.value = true
}// 导出
const downErrorExcel = () => {let fileName = '错误提示.xlsx'if (!blobData.value) {return}const blob = new Blob([blobData.value], { type: 'application/vnd.ms-excel' })const url = URL.createObjectURL(blob)downloadCommon(url, fileName)
}// 下载处理
const downloadCommon = (url: string, fileName: string) => {const link = document.createElement('a')link.style.display = 'none'link.href = urllink.setAttribute('download', fileName)document.body.appendChild(link)link.click()document.body.removeChild(link) // 下载完成移除元素
}

控制台输出为

axios拦截器输出为

解决问题1

由于后端返回文件时,前端必须设置responseType为blob,否则导出的excel会由于格式问题,打不开;

// 上传excel
const apiImportExcel = (params) => {return axiosBizcenterMarketingAct.request({url: 'https"//www.test.com/importExcelOptLessNum',method: 'post',responseType: 'blob',data: params})
}

情况2:导入成功,返回的内容为blob类型,json字符读取不到

如下图:控制台上方为拦截器输出内容,下方为拿到的data数据

但是当设置了响应格式为blob,则当后端返回json格式时,前端只能读到blob数据,blob数据看不到里面的内容。

相信大家看到了虽然返回都是blob格式,但是情况1和情况2返回的blob格式的type不一样。所以可以如下处理:

解决问题2:

处理代码如下:

// 上传excel,失败下载excel,成功返回msg
const uploading = async (data) => {uploadLoading.value = truelet file = data.filelet params = new FormData()params.append('file', file)let res = await apiImportExcel(params)console.log(res, 1234)if(res.type === 'text/xml') {isShowDownload.value = trueuploadMessage.value = '处理成功,成功导入'} else {blobData.value = resisShowDownload.value = trueuploadMessage.value = '处理失败,请整理表格后重新上传文档'}uploadLoading.value = falsedialogVisible.value = true
}

情况3:第三种情况和第二种情况怎么区分?

由于情况2和情况3返回都是json格式的问题,提示用户接口处理是否成功,所以正常的流程是后端接口返回的什么样的字符串,前端页面直接提示用户接口处理结果,而且目前是三种情况,将来扩展可能接口出现第四种第五种情况,所以使用上面的type判断,并不合适。

解决问题3:

不设置responseType为blob,会导致excel因为格式问题打不开,所以只能让接口返回blob格式,那就只能当接口返回类型为text/xml的时候,将blob解析成json格式,然后再读取json字符串了。

如何解析blob格式呢?下面有三种方法:

// 方法1const getJSONObjectFromBlob = (blob: Blob) => {const reader = new FileReader()reader.readAsArrayBuffer(blob)reader.onload = function () {console.info('reader.result>>>', reader.result) //ArrayBuffer {}//将 ArrayBuffer  转换成Blobconst buf = new Uint8Array(reader.result as ArrayBuffer)let enc = new TextDecoder('utf-8')let text = enc.decode(buf)try {const obj = JSON.parse(text)return obj} catch (error) {console.error('解析错误', error)return error}}}// 方法2const getJSONObjectFromBlob = (blob: Blob) => {const text = await (new Response(blob)).text();try {const obj = JSON.parse(text)return obj} catch (error) {console.error('解析错误', error)return error}}// 方法3const getJSONObjectFromBlob = (blob: Blob) => {const text = await blob.text();try {const obj = JSON.parse(text)return obj} catch (error) {console.error('解析错误', error)return error}}

看到这里,大家可能看到方法2和方法3都是读取Blob对象原型链上的text()方法进行解析,其实text()方法就是根据方法1这样设计的,不过目前这个方法1有点小瑕疵,大家能够发现吗?

方法1中使用FileReader对象去读取blob,然后通过onload去解析,不知道大家是否了解onload事件,onload是一个异步任务,所以js引擎走到这里不会去执行内部逻辑,而是等函数执行完才去宏任务队列中取出它,并执行。那函数还有未执行呢?走到这里,函数还没有返回值,所以大家应该猜到了吧,这里会返回undefined。

那怎么解决呢?大家有没有想到await和async关键字,但是使用这两个关键字,必须要是一个promise,所以把方法1改造成返回promise,然后去读取json对象,使用await关键字等待,promise响应再执行后续操作,就可以啦~~~

代码如下:


const getTextFromBlob = (blob: Blob): Promise<string> => {//将Blob 对象转换成 ArrayBufferreturn new Promise((resolve, reject) => {const reader = new FileReader()reader.readAsArrayBuffer(blob)reader.onload = function () {console.info('reader.result>>>', reader.result) //ArrayBuffer {}// 经常会遇到的异常 Uncaught RangeError: byte length of Int16Array should be a multiple of 2// const buf = new int16array(reader.result);// console.info(buf);//将 ArrayBuffer  转换成Blobconst buf = new Uint8Array(reader.result as ArrayBuffer)let enc = new TextDecoder('utf-8')resolve(enc.decode(buf))}reader.onerror = function (e) {console.error('转换成ArrayBeffer失败')reject(e)}})
}
// 解析 text/xml类型的blob, 成为JSON对象(失败则是json字符串)
export async function getJSONObjectFromBlob(blob: Blob): Promise<Record<string, unknown> | unknown> {let text = ''try {text = await getTextFromBlob(blob)const obj: Record<string, unknown> = JSON.parse(text)return obj} catch (error) {return error}
}

好了,为了能够通熟易懂,我还是使用了最简单的方法,代码如下:

const apiImportExcel = (params) => {return axiosBizcenterMarketingAct.request({url: 'https"//www.test.com/importExcelOptLessNum',method: 'post',data: params})
}
// 解析application/json类型的blob, 成为JSON对象(失败则是json字符串)const getJSONObjectFromBlob = (blob: Blob) => {const text = await blob.text();try {const obj = JSON.parse(text)return obj} catch (error) {console.error('解析错误', error)return error}}// 上传excel,失败下载excel,成功返回msgconst uploading = async (data) => {uploadLoading.value = truelet file = data.filelet params = new FormData()params.append('file', file)let res = await apiImportExcel(params)if (res.type === 'application/json') {// 读取BlobgetJSONObjectFromBlob(res).then((res) => {uploadMessage.value = res.msg})} else {blobData.value = resisShowDownload.value = trueuploadMessage.value = '处理失败,请整理表格后重新上传文档'}uploadLoading.value = falsedialogVisible.value = true}const downloadCommon = (url: string, fileName: string) => {const link = document.createElement('a')link.style.display = 'none'link.href = urllink.setAttribute('download', fileName)document.body.appendChild(link)link.click()document.body.removeChild(link) // 下载完成移除元素}

写到这里,有人会想到使用axios去请求接口会出现这种情况,那使用fetch呢?window对象自带的请求接口的方法,目前兼容性已经满足大部分浏览器了,所以我又做了以下内容

使用fetch请求

我们直接改造上面的uploading函数就行,说干就干

    // 上传excel,失败下载excel,成功返回msgconst uploading = async (data) => {uploadLoading.value = truelet file = data.filelet params = new FormData()params.append('file', file)window.fetch("https//www.xxx.com/importExcelOptLessNum", {method: 'post',body: params,headers: {'Authorization': accessToken,}}).then(res => {console.log(res, '----1---')return res.json();// return res.blob();}).tnen(res => {console.log(res, '0----3---------')blobData.value = res;isShowDownload.value = trueuploadMessage.value = '处理失败,请整理表格后重新上传文档';}).catch(err => {console.error(err)});uploadLoading.value = falsedialogVisible.value = true}

结果就是不行,从上图中可以看到,fetch确实不需要在请求头这里设置响应体类型,但是当数据响应给客户端时,必须要调用Response中的json()方法或者blob()方法,但在这之前,无法判断res是什么数据类型。

总结一下:

虽然情况1和情况2两次的blob的类型不一致,一个是application/vnd.ms-excel类型,一个是text/xml,但是由于第三种情况的介入,必须要获取到后端返回的json格式数据显示。

设置了responseType为blob类型,接口返回的数据如下:

没有设置responseType时,接口返回的数据如下:

目前是 解析 text/xml类型的blob, 成为JSON对象。

更多关于Blob对象的知识,可以点击链接查看:https://developer.mozilla.org/zh-CN/docs/Web/API/Blob

如果大家有什么更好的处理方法,欢迎评论区讨论~~~

当导入导出为同一个接口时,会产生什么样的“化学反应”?相关推荐

  1. oracle 导出写入文件失败怎么办,编辑dmp文件解决导入导出问题(oracle 922错误 ,缺少或无效选项)...

    导入导出的dmp文件时出现如下错误 经由常规路径导出由EXPORT:V09.02.00创建的文件 已经完成ZHS16GBK字符集和AL16UTF16 NCHAR 字符集中的导入 IMP-00017: ...

  2. 关于MSSQL导入导出时主键与约束丢失的问题解决

    导入数据时,使用默认选项,会丢失主键.约束.默认值等属性,按如下步骤操作: -->导出向导  -->选择数据源  -->选择目的  -->指定表复制或查询:不要使用默认选项,选 ...

  3. SqlServer的SSIS导入导出数据时找不到连接错误处理

    SqlServer的SSIS导入导出数据时找不到连接错误处理 报错: 找不到连接"SourceConnectionOLEDB".如果找不到特定的连接元素,Connections集合 ...

  4. oracle导入java包时出错,Oracle导入导出的常见错误

    做数据的导入导出操作,最常用的就是imp/exp和impdp/expdp,经常会碰见各种错误,之前总结过一些,<解决导入过程中出现的ORA-02289错误>.<生产数据导入测试环境碰 ...

  5. ORACLE数据库在导入导出时序列不一致的问题

    ORACLE数据库在导入导出时序列不一致的问题 在使用ORACLE数据库时,当给一个表设置自增字段时,我们经常会使用到序列+触发器来完成.但当你需要对数据库进行导入导出时,序列很容易出问题. 当你将数 ...

  6. abaqus生成adams柔性体_专栏 | HyperMesh_To_Abaqus接口——模型导入导出问题

    作者介绍 TechmanLXS 硕士 十余年工程经验擅长Hypermesh建模,Hyperworks全平台分析软件,abaqus软件.整车级被动安全(ls-dyna.Radioss),零部件级(mol ...

  7. oracle 39083,oracle数据库导入导出时ORA-39083;ORA-00439错误解决思路

    ORA-39083: Object type TABLE:TEST.TEST_SS_NAME failed to create with error: ORA-00439: feature not e ...

  8. 下载ug时java更新未完成_UG导入导出Dwg,Dxf文件提示:转换未完成,网上说的方法都试了一遍没用怎么办?...

    这是因为导不出DWG/DXF文件的原因有多种,你找到的解决方案可能并不是你所在的问题,也有可能是你没有按解决方案中的做到位. 你可以按以下几个原因排查: 1.高版本NX软件,在导入DWG\DXF的时候 ...

  9. easyexcel导入时读不到数据_SpringBoot中EasyExcel实现Excel文件的导入导出

    前言 在我们日常的开发过程中经常会使用Excel文件的形式来批量地上传下载系统数据,我们最常用的工具是Apache poi,但是如果数据到底上百万时,将会造成内存溢出的问题,那么我们怎么去实现百万数据 ...

  10. oracle 39083错误,Oracle数据库导入导出时,ORA-39083;ORA-00439错误解决思路

    ORA-39083: Object type TABLE:"TEST"."TEST_SS_NAME" failed to create with error: ...

最新文章

  1. YAML开源库yaml-cpp简介及使用
  2. combo:机器学习模型合并工具库
  3. 医学图像-颅内出血(转载+整理)
  4. 使用SAP WebIDE创建开发Java应用,并且在浏览器里调试
  5. RISC-V工具链环境(基于Debian/Linux操作系统)
  6. java中datetime类型转换,Java中日期格式和其他类型转换详解
  7. VMware虚拟机下安装Ubuntu16.04镜像完整教程
  8. [No000014A]Linux简介与shell编程
  9. Android事件处理之处理键盘事件
  10. [System Design] 系统设计 (2) -- 数据库设计
  11. Zuul使用Ribbon配置自动重试
  12. 免费的html模板开源网站
  13. contiki CC2530 CC2430例子描述
  14. [python爬虫] Selenium爬取新浪微博内容及用户信息
  15. smtp匿名邮件发送小记
  16. Ubuntu 编译最新LLVM套件:LLVM 16.0
  17. 程序员夏天穿格子衫,那么冬天穿什么?答案扎心了
  18. Android开发仿微信支付宝的支付密码布局
  19. python 编码gbk_python 处理中文文件时的编码问题,尤其是utf-8和gbk
  20. [NFC]NFC 客户 Support 流程

热门文章

  1. Wiki引擎mediawiki
  2. JumpServer登录提示连接WebSocket失败
  3. 如何关掉visual studio 2012 实时调试器
  4. 程序化交易逆境中的奋斗史!
  5. 学习笔记之 初试Linux遇到的问题
  6. c语言kill暂停和恢复进程,Linux暂停和恢复进程
  7. 解决MySql保存数据java.sql.SQLException: Incorrect string value: ‘\xF0\x9F\x91\x87\xE5\x91...‘
  8. C 语言 —— 命名规则
  9. ⛽zipkin2.reporter.InMemoryReporterMetrics导致服务器CPU100%及应用OOM问题排查和解决
  10. Byond Compare软件