如何将响应文件数据转为可下载文件?Blob生成文件不可读排查
如何将API响应转换为可下载文件URL?生成的文件无法读取问题排查
我尝试用Blob方法把API响应转成可下载文件URL,但生成的文件无法读取,问题出在哪?
我的尝试
let blob = new Blob([data.data], {type: "octet/stream"}); var url = window.URL.createObjectURL(blob); window.location.assign(url);
获取文件数据的API请求
export const getDocumentByFileName = async (fileName: string) => { const client = await Client(); const response = await client.get(`${endpoint}/Documents/Get?fileName=${fileName}`, { responseType: 'blob', }); if (!response.ok) { console.error('GET Document by fileName - ' + response.problem, response.data); return response; } // 204 No Content return response; };
包含文件的响应数据
let data = { "duration": 92, "problem": null, "originalError": null, "ok": true, "status": 200, "headers": { "date": "Thu, 04 Aug 2022 10:36:28 GMT", "server": "Kestrel" }, "config": { "url": "Documents/Get?fileName=afbaa8fb-2669-4cf1-ad69-726a408934f6..docx", "method": "get", "headers": { "Accept": "application/json", "locale": "en-gb" }, "params": { "responseType": "arraybuffer" }, "baseURL": "/", "transformRequest": [ null ], "transformResponse": [ null ], "timeout": 0, "xsrfCookieName": "XSRF-TOKEN", "xsrfHeaderName": "X-XSRF-TOKEN", "maxContentLength": -1, "maxBodyLength": -1, "transitional": { "silentJSONParsing": true, "forcedJSONParsing": true, "clarifyTimeoutError": false } }, "data": "PK\u0003\u0004\u0014\u0000\u0006\u0000\b\u0000\u0000\u0000!\u0000ߤ�lZ\u0001\u0000\u0000 \u0005\u0000\u0000\u0013\u0000\b\u0002[Content_Types].xml �\u0004\u0002(�\u0000\u0002\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" }
问题根源
- 响应格式配置冲突:你的API请求中,虽然设置了
responseType: 'blob',但响应的config.params里包含了responseType: 'arraybuffer'——这会把responseType当成URL参数传给后端,而非Axios的响应解析配置。Axios默认会把二进制数据解析为UTF-8字符串,导致文件字节被篡改,生成的文件自然无法读取。 - 下载方式不严谨:直接使用
window.location.assign(url)触发下载,部分浏览器可能无法正确识别文件类型或文件名,增加读取失败概率。
解决方案
步骤1:修正API请求配置
移除params中的responseType,确保Axios的responseType配置正确生效:
export const getDocumentByFileName = async (fileName: string) => { const client = await Client(); const response = await client.get(`${endpoint}/Documents/Get?fileName=${fileName}`, { responseType: 'arraybuffer', // 推荐用arraybuffer,后续转换更灵活 headers: { 'Accept': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' // 明确指定文件类型 } }); if (!response.ok) { console.error('GET Document by fileName - ' + response.problem, response.data); return response; } return response; };
步骤2:正确转换并触发下载
如果已经拿到被解析为字符串的二进制数据,先将其转回ArrayBuffer,再创建Blob并通过a标签触发下载:
// 将Unicode字符串转回ArrayBuffer function stringToBuffer(str) { const buffer = new Uint8Array(str.length); for (let i = 0; i < str.length; i++) { buffer[i] = str.charCodeAt(i); } return buffer.buffer; } // 处理下载 const arrayBuffer = stringToBuffer(data.data); const blob = new Blob([arrayBuffer], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); const url = window.URL.createObjectURL(blob); // 创建a标签触发下载 const downloadLink = document.createElement('a'); downloadLink.href = url; downloadLink.download = '目标文件名.docx'; // 替换为实际文件名 document.body.appendChild(downloadLink); downloadLink.click(); // 清理资源 document.body.removeChild(downloadLink); window.URL.revokeObjectURL(url);
如果API请求修正后直接拿到ArrayBuffer或Blob,可以简化代码:
// 若response.data是ArrayBuffer const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); // 后续下载逻辑同上
内容的提问来源于stack exchange,提问作者BennKingy
相关产品推荐
相关产品推荐

