前端封装的一个下载文件的函数
export const downloadFile = (fileInfo?: any) => {
const { url, params } = fileInfo;
return new Promise((reslove, reject) => {
axios({
method: "get",
url: url,
responseType: "blob", //服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream',默认是'json'
timeout: 0, // 默认值是 `0` (永不超时)
params: params
})
.then(({ data, headers }) => {
let fileName = url.substr(url.lastIndexOf("/") + 1);
const contentDisposition = headers["content-disposition"];
if (contentDisposition) {
const name1 = contentDisposition.split(";")[2];
if (name1) {
const name2 = name1.split("filename*=")[1];
if (name2) {
const name3 = name2.split("''")[1];
if (name3) {
const name4 = name3.split(".")[0];
if (name4) {
fileName = decodeURI(name4);
}
}
}
}
}
if (!data) {
reslove("");
return;
}
let blobType = "";
const contentType = headers["content-type"];
if (contentType) {
blobType = contentType;
}
const blob = new Blob([data], {
type: blobType
});
// if (window.navigator.msSaveOrOpenBlob) {
// //兼容IE10
// navigator.msSaveBlob(blob, fileName);
// } else {
const URL = window.URL || window.webkitURL;
const href = URL.createObjectURL(blob); //创建新的URL表示指定的blob对象
const a = document.createElement("a"); //创建a标签
a.style.display = "none";
a.href = href; // 指定下载链接
a.download = fileName; //指定下载文件名
document.body.appendChild(a);
a.click(); //触发下载
URL.revokeObjectURL(a.href); //释放URL对象
document.body.removeChild(a); //下载完成移除
// }
// 这里也可以不创建a链接,直接window.open(href)也能下载
reslove("");
})
.catch(err => {
console.log("downloadFile err", err);
reject();
});
});
};
逐步解释
axios({
method: "get",
url: url,
responseType: "blob", //服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream',默认是'json'
timeout: 0, // 默认值是 `0` (永不超时)
params: params
})
responseType
这是发送axios请求,url是要下载的文件地址,params是其他的自定义参数
设置responseType为blob,在 Axios 中,responseType 用于指定服务器响应的数据类型。以下是 responseType 的可选值及其含义:
1. arraybuffer
-
描述:表示响应数据将作为
ArrayBuffer返回。 -
用途:通常用于处理二进制数据,例如图像、音频、视频文件等。
2. blob
-
描述:表示响应数据将作为
Blob返回。 -
用途:通常用于处理文件下载。
3. document
-
描述:表示响应数据将作为
Document对象返回。 -
用途:用于处理 HTML/XML 文档。
4. json
-
描述:表示响应数据将作为 JSON 对象返回。默认值。
-
用途:用于处理 JSON 格式的数据。
5. text
-
描述:表示响应数据将作为
string返回。 -
用途:用于处理文本数据。
6. stream
-
描述:表示响应数据将作为
stream返回(仅在 Node.js 环境中可用)。 -
用途:用于处理流数据,通常用于文件下载或大数据量传输。
.then(({ data, headers }) => {
let fileName = url.substr(url.lastIndexOf("/") + 1);
const contentDisposition = headers["content-disposition"];
if (contentDisposition) {
const name1 = contentDisposition.split(";")[2];
if (name1) {
const name2 = name1.split("filename*=")[1];
if (name2) {
const name3 = name2.split("''")[1];
if (name3) {
const name4 = name3.split(".")[0];
if (name4) {
fileName = decodeURI(name4);
}
}
}
}
}
if (!data) {
reslove("");
return;
}
let blobType = "";
const contentType = headers["content-type"];
if (contentType) {
blobType = contentType;
}
const blob = new Blob([data], {
type: blobType
});
// if (window.navigator.msSaveOrOpenBlob) {
// //兼容IE10
// navigator.msSaveBlob(blob, fileName);
// } else {
const URL = window.URL || window.webkitURL;
const href = URL.createObjectURL(blob); //创建新的URL表示指定的blob对象
const a = document.createElement("a"); //创建a标签
a.style.display = "none";
a.href = href; // 指定下载链接
a.download = fileName; //指定下载文件名
document.body.appendChild(a);
a.click(); //触发下载
URL.revokeObjectURL(a.href); //释放URL对象
document.body.removeChild(a); //下载完成移除
// }
// 这里也可以不创建a链接,直接window.open(href)也能下载
reslove("");
})
.catch(err => {
console.log("downloadFile err", err);
reject();
});
then和catch分别处理axios成功和失败的结果
then
{data,header}是从axios返回的结果res身上解构的
let fileName = url.substr(url.lastIndexOf("/") + 1);
const contentDisposition = headers["content-disposition"];
if (contentDisposition) {
const name1 = contentDisposition.split(";")[2];
if (name1) {
const name2 = name1.split("filename*=")[1];
if (name2) {
const name3 = name2.split("''")[1];
if (name3) {
const name4 = name3.split(".")[0];
if (name4) {
fileName = decodeURI(name4);
}
}
}
}
}
fileName是从url参数上获取到的文件名,url.substr(url.lastIndexOf("/") + 1)是截取最后一个/到最后的字符串,
假设 url 的值是 https://example.com/files/document.pdf:
url.lastIndexOf("/"):找到 URL 中最后一个斜杠/的位置。在这个例子中,它会返回 24,因为最后一个斜杠的位置是第 24 个字符。url.substr(url.lastIndexOf("/") + 1):从url中提取从第 25 个字符(24 + 1)开始的所有字符,这里就是document.pdf。
const contentDisposition = headers["content-disposition"]; 这一行代码用于从响应头中获取 Content-Disposition 字段的值。Content-Disposition 头通常用于指示如何处理响应内容,尤其是在文件下载的场景中。它可以包含文件名信息,帮助客户端正确命名下载的文件。
详细解释
当服务器发送文件下载响应时,响应头中可能包含 Content-Disposition 字段,如下所示:
css
复制代码
Content-Disposition: attachment; filename="example.txt"
这个字段指示浏览器以附件的形式处理响应内容,并将文件名设为 example.txt。在 Axios 响应对象中,响应头可以通过 headers 属性访问。
if (contentDisposition) {
const name1 = contentDisposition.split(";")[2];
if (name1) {
const name2 = name1.split("filename*=")[1];
if (name2) {
const name3 = name2.split("''")[1];
if (name3) {
const name4 = name3.split(".")[0];
if (name4) {
fileName = decodeURI(name4);
}
}
}
}
}
这段代码用于从 Content-Disposition 响应头中解析出文件名。以下是详细的解析步骤:
-
检查
Content-Disposition:javascript 复制代码 if (contentDisposition) {首先,检查响应头中是否存在
Content-Disposition字段。 -
分割
Content-Disposition:javascript 复制代码 const name1 = contentDisposition.split(";")[2];使用分号
;分割Content-Disposition字段,并取第三个部分(索引为2),因为文件名通常在第三部分。Content-Disposition字段通常类似于attachment; filename="example.txt"或attachment; filename*=UTF-8''example.txt。 -
检查并分割
filename*=:javascript 复制代码 if (name1) { const name2 = name1.split("filename*=")[1];检查第三部分是否存在,并尝试使用
filename*=分割。filename*=通常用于指定编码格式和文件名。 -
分割编码和文件名:
javascript 复制代码 if (name2) { const name3 = name2.split("''")[1];如果
filename*=存在,再使用''分割,取第二部分(索引为1),这部分通常是文件名。 -
分割文件名和扩展名:
javascript 复制代码 if (name3) { const name4 = name3.split(".")[0];如果文件名存在,再使用点
.分割,取第一部分(索引为0),即文件名(不含扩展名)。 -
解码文件名:
javascript 复制代码 if (name4) { fileName = decodeURI(name4); }最后,如果文件名存在,使用
decodeURI函数对其进行解码。
示例 Content-Disposition 响应头
假设 Content-Disposition 头为:
css
复制代码
Content-Disposition: attachment; filename*=UTF-8''example.txt
- 分割后得到
["attachment", " filename*=UTF-8''example.txt"]。 - 取第三部分(实际上是第二部分,因为数组索引从0开始)。
- 进一步分割
filename*=,得到["UTF-8", "example.txt"]。 - 再分割
'',得到["UTF-8", "example.txt"]。 - 使用
.分割example.txt,得到["example", "txt"]。 - 最终文件名为
example。
if (!data) {
reslove("");
return;
}
let blobType = "";
const contentType = headers["content-type"];
if (contentType) {
blobType = contentType;
}
const blob = new Blob([data], {
type: blobType
});
这段代码的功能是处理从服务器获取的响应数据,并根据响应头中的 Content-Type 创建一个 Blob 对象。以下是对这段代码的逐行解释:
-
检查数据是否为空:
javascript 复制代码 if (!data) { reslove(""); return; }- 如果
data为空,调用resolve结束 Promise 并返回空字符串。
- 如果
-
初始化
blobType:javascript 复制代码 let blobType = "";- 初始化
blobType为一个空字符串。blobType用于存储响应数据的 MIME 类型。
- 初始化
-
检查
Content-Type响应头:javascript 复制代码 const contentType = headers["content-type"]; if (contentType) { blobType = contentType; }- 获取响应头中的
Content-Type字段。如果存在,将其赋值给blobType。
- 获取响应头中的
-
创建
Blob对象:javascript 复制代码 const blob = new Blob([data], { type: blobType });- 使用响应数据创建一个新的
Blob对象,并指定其类型为blobType。
- 使用响应数据创建一个新的
const URL = window.URL || window.webkitURL;
const href = URL.createObjectURL(blob); //创建新的URL表示指定的blob对象
const a = document.createElement("a"); //创建a标签
a.style.display = "none";
a.href = href; // 指定下载链接
a.download = fileName; //指定下载文件名
document.body.appendChild(a);
a.click(); //触发下载
URL.revokeObjectURL(a.href); //释放URL对象
document.body.removeChild(a); //下载完成移除
// }
// 这里也可以不创建a链接,直接window.open(href)也能下载
reslove("");
这段代码用于在浏览器中创建一个用于下载文件的链接,并自动触发下载。以下是逐行解释:
-
获取 URL 创建函数:
javascript 复制代码 const URL = window.URL || window.webkitURL;- 获取
URL创建函数,兼容不同浏览器。如果浏览器支持window.URL,则使用window.URL,否则使用window.webkitURL。
- 获取
-
创建 Blob 对象的 URL:
javascript 复制代码 const href = URL.createObjectURL(blob);- 使用
createObjectURL方法为blob对象创建一个临时的 URL。这个 URL 可以用来访问blob的内容。
- 使用
-
创建
<a>标签:javascript 复制代码 const a = document.createElement("a");- 创建一个新的
<a>标签元素。
- 创建一个新的
-
隐藏
<a>标签:javascript 复制代码 a.style.display = "none";- 将
<a>标签隐藏(设置display: none),以免影响页面布局。
- 将
-
设置下载链接:
javascript 复制代码 a.href = href;- 将
<a>标签的href属性设置为上一步创建的blobURL。
- 将
-
设置下载文件名:
javascript 复制代码 a.download = fileName;- 将
<a>标签的download属性设置为下载文件的文件名。
- 将
-
添加
<a>标签到文档中:javascript 复制代码 document.body.appendChild(a);- 将
<a>标签添加到文档的body中,以使其成为 DOM 的一部分。
- 将
-
触发下载:
javascript 复制代码 a.click();- 程序化地触发
<a>标签的click事件,开始下载文件。
- 程序化地触发
-
释放 URL 对象:
javascript 复制代码 URL.revokeObjectURL(a.href);- 调用
revokeObjectURL方法释放之前创建的blobURL,释放内存。
- 调用
-
移除
<a>标签:javascript 复制代码 document.body.removeChild(a);- 下载完成后,将
<a>标签从文档中移除,清理 DOM。
- 下载完成后,将
-
完成 Promise:
javascript 复制代码 resolve("");- 调用
resolve,标记 Promise 已完成,并返回空字符串。
- 调用