前端下载文件时文件名不对Blob解决方案
作者:weixin_60474741
一、问题现象
前端页面有个下载按钮,点击后文件成功下载,但文件名和预期不符:
- 期望文件名:变动.docx(自定义名称)。
- 实际文件名:
7a60023d64d34fd298cfff5b31001615.docx(URL 里的 “原始存储名”)。
二、为什么会这样?(核心原因)
这个问题的本质是 “跨域资源限制” + “文件名数据源没处理好” 共同导致的。
1. 跨域让a.download失效
前端下载文件,最常用的方式是用 <a> 标签:
<a href="http://跨域的下载链接" rel="external nofollow" download="期望的文件名.docx">下载</a>
但如果 href 指向的是跨域资源(比如前端页面是 localhost:8080,下载链接是 192.168.2.23:9000),浏览器的安全策略会让 download 属性直接失效—— 此时浏览器会忽略你设置的 “期望文件名”,转而从 URL 或服务器响应头里取文件名(通常是服务端存储的 “原始哈希名”)。

2. 文件名的 “数据源” 没拿到正确值
即使没有跨域问题,如果前端代码里获取文件名的逻辑有漏洞(比如没从后端响应中拿 “自定义文件名”,或者文件对象本身的 name 属性不对),也会导致文件名不符合预期。
三、Blob 是什么?
Blob 的全称是 Binary Large Object(二进制大对象)。简单来说:
- Blob 是浏览器里的一个 “容器”,专门用来存储二进制数据(比如图片、视频、文档的二进制内容)。
- 你可以把 “网络上的文件”“用户上传的文件” 先转成 Blob,再用 Blob 做很多事(比如生成临时预览链接、实现 “自定义文件名下载” 等)。
Blob 最核心的用法是配合 URL.createObjectURL(blob) —— 它能把 Blob 转成一个本地临时 URL(类似 blob:http://xxx/abcdef)。这个 URL 是 “同域” 的,不会有跨域问题,因此能绕开浏览器的跨域限制~
四、解决方案:用 Blob 绕开跨域,确保文件名正确
下面结合代码,一步步解决问题。
步骤 1:确保能拿到 “自定义文件名”
首先,要从后端接口响应或文件对象中,明确拿到 “期望的文件名”(比如 “变动.docx”)。
假设后端在 “文件上传 / 查询” 接口中,会返回文件名,那前端需要把这个文件名 “注入” 到文件对象里。示例:
// 从后端接口获取文件列表后,处理成前端组件能识别的格式
fileList.value = response.data.fileList.map(file => ({
name: file.fileName, // 把后端返回的fileName设为文件的name
url: file.downloadUrl, // 下载链接
response: {
data: {
fileName: file.fileName, // 明确存储“自定义文件名”
ossId: file.ossId // 其他文件标识(可选)
}
},
status: 'success' // 标记文件状态(可选)
}));
这样,文件对象里的 file.name 或 file.response.data.fileName 就能拿到 “变动.docx” 了~
步骤 2:用 Blob 处理 “跨域下载”
当下载链接是跨域时,我们可以通过 fetch(或 axios)先获取文件的Blob 流,再用 URL.createObjectURL 生成 “本地临时 URL”,最后用这个 URL 下载(此时 a.download 会生效)。
const handleDownload = (file: any) => {
// 1. 拿到下载链接和自定义文件名
const downloadUrl = file.downloadUrl || file.response?.data?.url;
const fileName = file.response?.data?.fileName || file.name || '未命名文件';
// 2. 非图片文件:用Blob处理跨域下载
fetch(downloadUrl)
.then(response => {
if (!response.ok) {
throw new Error('网络请求失败');
}
return response.blob(); // 把响应数据转成Blob
})
.then(blob => {
// 3. 生成Blob的“本地临时URL”
const blobUrl = URL.createObjectURL(blob);
// 4. 构造<a>标签,实现下载
const a = document.createElement('a');
a.href = blobUrl; // 本地临时URL(无跨域问题)
a.download = fileName; // 自定义文件名(此时会生效)
a.style.display = 'none'; // 隐藏a标签
document.body.appendChild(a);
// 5. 触发下载
a.click();
// 6. 清理资源(避免内存泄漏)
document.body.removeChild(a);
setTimeout(() => {
URL.revokeObjectURL(blobUrl); // 释放临时URL
}, 100);
ElMessage.success(`文件 ${fileName} 开始下载~`); // Element Plus 提示
})
.catch(error => {
console.error('下载失败:', error);
ElMessage.error('下载失败,请稍后重试');
});
};
步骤 3:图片文件的特殊处理(可选优化)
如果是图片文件(如 jpg、png、gif 等),浏览器支持 “直接预览”,可以用 target="_blank" 在新标签页打开,体验更友好:
const handleDownload = (file: any) => {
const downloadUrl = file.downloadUrl || file.response?.data?.url;
const fileName = file.response?.data?.fileName || file.name || '未命名文件';
// 判断是否为图片文件
const isImage = /\.(jpg|jpeg|png|gif|webp)$/i.test(fileName);
if (isImage) {
// 图片:新标签页打开预览
const a = document.createElement('a');
a.href = downloadUrl;
a.target = '_blank'; // 新标签页打开
a.click();
ElMessage.success(`正在预览图片:${fileName}`);
} else {
// 非图片:用Blob处理跨域下载(同步骤2)
fetch(downloadUrl)
.then(res => res.blob())
.then(blob => {
// ... 同步骤2的Blob处理逻辑
});
}
};
五、总结
解决 “下载文件名不符合预期” 的核心思路是:
- 确保能拿到正确的自定义文件名:从后端响应或文件对象中,明确存储并获取 “期望的文件名”。
- 处理跨域限制:通过
Blob将 “跨域资源” 转成 “同域本地临时资源”,让a.download生效。
而 Blob 作为 “二进制大对象”,是前端操作文件流的核心工具。URL.createObjectURL(blob) 是关键 API。
通过将跨域资源先获取到本地转为Blob对象,再创建同源的Blob URL,这样就绕过了跨域限制,确保了 download 属性能够正确生效,使用指定的文件名下载。
到此这篇关于前端下载文件时文件名不对Blob解决方案的文章就介绍到这了,更多相关前端下载文件时文件名不对内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
