如何创建包含ANSI(windows-1252)数据而非UTF-8的Blob对象
解决Angular中PDF下载时二进制数据被UTF-8编码破坏的问题
问题根源
你遇到的核心问题是把二进制PDF数据当成字符串处理了。当你将字符串类型的buffer传入Blob构造函数时,浏览器会自动用UTF-8编码重新解析这个字符串,导致原始二进制数据被篡改,文件大小翻倍且无法正常打开。PDF是二进制文件,根本不存在"ANSI/UTF-8编码"的说法——你需要的是原封不动保存原始二进制字节,而非处理文本编码。
解决方案步骤
修正API请求的响应类型
在Angular的HttpClient请求中,必须指定responseType: 'arraybuffer',确保拿到的是原始二进制数据,而非自动转换后的字符串:// 示例:获取PDF数据的API请求 this.http.get('/api/pdf/download', { responseType: 'arraybuffer' }) .subscribe((buffer: ArrayBuffer) => { this.saveAsPdfFile(buffer, 'example.pdf', 'application/pdf'); });修改保存方法的参数与实现
将buffer的类型从string改为ArrayBuffer或Uint8Array,直接用二进制数据创建Blob,不需要指定charset(对二进制文件无效):/** * 保存PDF文件到本地 * @param buffer 原始二进制PDF数据(ArrayBuffer类型) * @param fileName 保存的文件名 * @param fileType 文件类型 */ private saveAsPdfFile(buffer: ArrayBuffer, fileName: string, fileType: string): void { // 直接用ArrayBuffer创建Blob,无需指定charset const data: Blob = new Blob([buffer], { type: fileType }); // 使用a标签下载的方式 const downloadLink = document.createElement('a'); downloadLink.href = URL.createObjectURL(data); downloadLink.setAttribute('download', fileName); document.body.appendChild(downloadLink); downloadLink.click(); document.body.removeChild(downloadLink); URL.revokeObjectURL(downloadLink.href); // 释放URL对象,避免内存泄漏 }
为什么之前的尝试无效?
- 给Blob指定
charset=windows-1252是无效的,因为Blob的charset参数仅对文本类型有效,二进制文件不需要编码声明。 - 将二进制数据以字符串形式传递时,浏览器会把每个字节当成UTF-8字符处理,部分字节会被转义或扩展,导致原始数据完全损坏。
额外注意事项
- 如果使用FileSaver库,直接传入Blob对象而非URL,效果一致:
// 使用FileSaver的写法 FileSaver.saveAs(data, fileName); - 确保API接口返回的响应头
Content-Type是application/pdf,避免浏览器对响应做额外解析。
内容的提问来源于stack exchange,提问作者E Lewis
相关产品推荐
相关产品推荐

