You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

75 lines
2.5 KiB
TypeScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { fileDownload } from '@/api/modules/system/common';
export function useUrlDownload(file: { url: string; filename?: string }) {
/** 从 URL 截取兜底文件名 */
function getFileNameFromUrl(url: string) {
return url.split('/').pop() || url;
}
/** 从 Content-Disposition 中解析文件名(支持 filename* 与 filename */
function extractFileNameFromCD(cd?: string | null): string | undefined {
if (!cd) return;
// 1) 先处理 RFC5987 的 filename*
const starMatch = /filename\*\s*=\s*([^;]+)/i.exec(cd);
if (starMatch) {
const value = starMatch[1].trim().replace(/^"(.*)"$/, '$1'); // 去掉首尾引号
const rfc5987 = /^([^']*)'[^']*'(.*)$/.exec(value);
if (rfc5987) {
const encodedPart = rfc5987[2];
try {
return decodeURIComponent(encodedPart);
} catch (e) {
console.log('无法解码 RFC5987 编码的文件名:', e);
}
} else {
try {
return decodeURIComponent(value);
} catch (e) {
console.log('无法解码 URL 编码的文件名:', e);
}
return value;
}
}
// 2) 再处理普通 filename=
const normalMatch = /filename\s*=\s*([^;]+)/i.exec(cd);
if (normalMatch) {
return normalMatch[1].trim().replace(/^"(.*)"$/, '$1');
}
}
async function proxyDownload(url: string, filename?: string) {
// 1. 通过代理接口拿到 AxiosResponse<Blob>
const res = await fileDownload({ url });
// 2. 从响应头中取 Content-Disposition
const cd =
(res.headers['content-disposition'] as string | undefined) ?? (res.headers['Content-Disposition'] as string | undefined);
// 3. 计算最终文件名:前端传入 > 响应头 > URL > 'download'
let finalName = filename;
const cdName = extractFileNameFromCD(cd);
if (!finalName && cdName) finalName = cdName;
if (!finalName) finalName = getFileNameFromUrl(url) || 'download';
// 4. 触发浏览器下载
const blob = res.data as Blob;
const objectUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = objectUrl;
a.download = finalName;
document.body.appendChild(a);
a.click();
a.remove();
setTimeout(() => URL.revokeObjectURL(objectUrl), 1000);
}
const { url, filename } = file;
const name = filename || getFileNameFromUrl(url);
// 统一走后端代理,解决跨域
return proxyDownload(url, name);
}