vue3 POST请求中,文件流下载添加responseType: ‘arraybuffer‘的问题
问题:
let data = { fileId: 'sddfsfsfds' }
const res = await axios({
method: 'POST',
url: 'https://xxxxxxx/xxxxx',
data,
responseType: 'arraybuffer'
})
改写成 const res = await proxy.$httpPost('url', xxxxx, .... 的方式
解决:
假设你有一个封装了 Axios 请求的代理对象 proxy
,其中 $httpPost
是一个方法,用于发送 POST 请求。你需要将原始的 Axios 请求改写为使用这个代理对象的方法。
以下是如何将原始的 Axios 请求改写为使用 proxy.$httpPost
方法的示例:
import { ref, reactive } from 'vue';
import { useProxy } from 'path-to-your-proxy-module'; // 假设你有一个代理模块
export default {
setup() {
const proxy = useProxy(); // 获取代理对象
const data = reactive({ fileId: 'sddfsfsfds' }); // 使用reactive来使data响应式
const res = ref(null); // 用于存储响应结果
async function fetchData() {
try {
res.value = await proxy.$httpPost('https://xxxxxxx/xxxxx', data, {
responseType: 'arraybuffer' // 确保将响应类型设置为arraybuffer
});
} catch (error) {
console.error('请求失败:', error);
}
}
// 调用fetchData函数
fetchData();
return {
res,
fetchData
};
}
};
在这个组件中:
- 使用
reactive
来定义响应式的数据对象data
。 - 使用
ref
来定义响应式的结果变量res
。 - 定义了一个异步函数
fetchData
来处理 HTTP 请求。 - 使用
await
等待proxy.$httpPost
方法的响应。 - 使用
try...catch
结构来处理可能发生的错误。
请注意,这里的 useProxy
和 proxy.$httpPost
是假设的,你需要根据你的项目实际情况来调整。确保 $httpPost
方法接受正确的参数,并且能够处理响应类型。
此外,res.value
用于存储请求返回的数据,你可以在模板或其他计算属性中使用它。最后,你可以在组件的适当位置调用 fetchData
函数,例如在组件的生命周期钩子中,或者在用户触发的事件处理函数中。
遇到的另外一个问题:
如果responseType的值改为'blob',responseType: 'blob' // 确保将响应类型设置为blob,会发现可以下载,但是打开不了。而用responseType: 'arraybuffer' 就可以。初步判断应该是后端返回的数据格式问题,但是后端还没注意到这个点。
文件流下载基本原理:
- 从服务器获取数据流。
- 将数据流转换成Blob对象。
- 创建一个URL指向该Blob对象。
- 创建一个a标签,设置其href属性为该URL,download属性为文件名。
- 模拟点击a标签,触发文件下载。
- 完成下载后,释放URL对象。
实现过程也可以把下载函数封装成一个通用的方法:
/**
* data: 下载文件
* fileName: 文件名
* type: 下载文件类型
*/
export function downloadHandler(data, fileName, type) {
// 匹配任意文件类型:type : "application/octet-stream"
const blob = new Blob([data], { type: type || 'application/octet-stream' });
const downloadElement = document.createElement('a');
const href = window.URL.createObjectURL(blob);
downloadElement.href = href;
downloadElement.download = fileName;
document.body.appendChild(downloadElement);
downloadElement.click();
document.body.removeChild(downloadElement);
window.URL.revokeObjectURL(href);
}
这里只做一个参考,不一样的地方是传参,具体实现还要看实际需要。
// import axios from 'axios'
async function downloadFile(fileId) {
try {
// 错误传参方式:
// let params = { fileId: fileIds }
// cosnt res = await proxy.$httpGet('/xxxxxx/DownloadFileFromOss', { params, responseType: 'arraybuffer })
// cosnt res = await proxy.$httpGet('/xxxx/DownloadFileFromOss', { fileId: fileIds, responseType: 'arraybuffer })
// 上述写法错误
let data = { fileId: fileId }
let responseType = 'arraybuffer'
// const res = await axios({
// method: 'POST',
// url: 'https://xxxxx/xxxxx/DownloadFileFromOss',
// data,
// responseType: 'arraybuffer'
// }) // 一开始用这种原生的写法可以下载打开,但是考虑到域名那些可能会改,改用下面方法,结合修改http/index.js文件的post方法封装
const res = await proxy.$httpPost('/xxxx/DownloadFileFromOss', data, responseType)
// console.log('res-download', res)
cosnt getNameRes = await proxy.$httpGet('/xxxxx/GetFileName', { fileId: fileIds })
if (res?.data) {
const data = res.data
const name = getNameRes.data
let blob = new Blob([data], { type: res.header['content-type'] || 'application/octet-stream' }) // type: res.header['content-type']--使用获取的excel格式
const url = URL.createObjectURL(blob)
const alink = document.createElement('a')
alink.download = name
alink.style.display = 'none'
alink.href = url
document.body.appendChild(alink)
alink.click() // 点击下载
URL.revokeObjectURL(alink.href) // 释放掉blob对象
document.body.removeChild(alink) // 下载完成移除元素
}
}catch(err) {
console.log('error', err.message)
}
}
更多推荐
所有评论(0)