日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發(fā)布時間:2023/12/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 当导入导出为同一个接口时,会产生什么样的“化学反应”? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

業(yè)務需求中出現一個接口既有導入功能,又需要有導出功能,接口具體情況如下:

導入excel表格接口中,前端傳遞上傳的excel文檔,后端判斷文檔是否格式正常,如果格式正常,則返回json格式的成功數據,如果格式不成功,則返回錯誤的excel文檔,前端負責把錯誤的excel文檔導出,第三種情況,如果5s內再次導入文檔,則后端返回不能頻繁導入的錯誤json數據。

總結一下:

情況1:前端導入excel表格,觸發(fā)請求,后端響應文件,blob格式,導入數據失敗,前端導出文件;

情況2:前端導入excel表格,觸發(fā)請求,后端響應json格式,導入數據正常,存儲到數據庫中;

情況3:前端5s內再次導入excel表格,觸發(fā)請求,后端響應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:第三種情況和第二種情況怎么區(qū)分?

由于情況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有點小瑕疵,大家能夠發(fā)現嗎?

方法1中使用FileReader對象去讀取blob,然后通過onload去解析,不知道大家是否了解onload事件,onload是一個異步任務,所以js引擎走到這里不會去執(zhí)行內部邏輯,而是等函數執(zhí)行完才去宏任務隊列中取出它,并執(zhí)行。那函數還有未執(zhí)行呢?走到這里,函數還沒有返回值,所以大家應該猜到了吧,這里會返回undefined。

那怎么解決呢?大家有沒有想到await和async關鍵字,但是使用這兩個關鍵字,必須要是一個promise,所以把方法1改造成返回promise,然后去讀取json對象,使用await關鍵字等待,promise響應再執(zhí)行后續(xù)操作,就可以啦~~~

代碼如下:

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

如果大家有什么更好的處理方法,歡迎評論區(qū)討論~~~

總結

以上是生活随笔為你收集整理的当导入导出为同一个接口时,会产生什么样的“化学反应”?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。