Skip to content

Instantly share code, notes, and snippets.

@mrxf

mrxf/download.tsx

Last active Nov 9, 2020
Embed
What would you like to do?
xhr download file
import { Button, Card, message, Progress, Space } from "antd";
import Axios, { CancelTokenSource } from "axios";
import contentDisposition from "content-disposition";
import React, { useCallback, useRef, useState } from "react";
interface DownloadProps {}
const Download: React.FC<DownloadProps> = () => {
const cancelSource = useRef<CancelTokenSource | null>(null);
const [percentage, setPercentage] = useState<number>(0);
const triggerDownload = useCallback((data: any, fileName: string) => {
let url = window.URL.createObjectURL(new Blob([data]));
let link = document.createElement("a");
link.style.display = "none";
link.href = url;
link.setAttribute("download", fileName);
document.body.appendChild(link);
link.click();
}, []);
const onDownload = useCallback(
(url: string) => {
return new Promise(async (resolve, reject) => {
const CancelToken = Axios.CancelToken;
cancelSource.current = CancelToken.source();
try {
const response = await Axios.get(url, {
// 文件类型设置
responseType: "blob",
headers: {
Authorization: `Bearer Token`, // 授权信息
},
cancelToken: cancelSource.current.token,
onDownloadProgress(evt) {
setPercentage(Math.ceil((evt.loaded / evt.total) * 100));
},
});
if (response.status === 200) {
let fileName = "";
if ("content-disposition" in response.headers) {
// 从Header中获取文件名
const dispositionParams = contentDisposition.parse(
response.headers["content-disposition"]
).parameters;
fileName = dispositionParams["filename"];
}
triggerDownload(response.data, fileName);
resolve("success");
} else {
reject("response status" + response.status);
}
} catch (error) {
// Axios的错误类型,读取返回数据中的JSON内容
if (error.isAxiosError) {
// 因为数据默认设置为Blob文件类型,因此需要使用fileReader将数据从Blob中读取出来
const fr = new FileReader();
fr.onload = function () {
const result = JSON.parse((this.result as string) ?? "{}");
// 与后端协定的数据格式,根据实际情况改动
reject(result.message);
};
fr.readAsText(error.response.data);
} else {
// 其他错误类型,直接返回消息体
reject(error.message);
}
}
});
},
[triggerDownload]
);
const onClickDownload = useCallback(() => {
setPercentage(0);
onDownload("/api/download/attachment-image").then(
() => {
message.success("下载成功");
},
(err) => message.error(err)
);
}, [onDownload]);
const onCancel = useCallback(() => {
setPercentage(0);
cancelSource.current?.cancel("用户取消下载");
}, []);
const onClickUnAuthDownload = useCallback(() => {
onDownload("/api/download/download-unauth").then(
() => {
message.success("下载成功");
},
(err) => message.error(err)
);
}, [onDownload]);
return (
<div className='inner-card'>
<Card>
<div style={{ display: "flex", justifyContent: "center" }}>
<Space>
<Button type='primary' disabled={ !!percentage && percentage !== 100 } onClick={onClickDownload}>
开始下载
</Button>
<Button type='dashed' onClick={onCancel}>
取消下载
</Button>
<Progress type='circle' percent={percentage} />
</Space>
</div>
</Card>
<Card>
<Button onClick={onClickUnAuthDownload} danger>
测试下载错误
</Button>
</Card>
</div>
);
};
export default Download;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment