如何通过Ajax调用下载C#控制器返回的FileContentResult PDF文件?
问题:前端无法正确下载后端返回的PDF字节数组
后端C#控制器返回PDF的代码:
return new FileContentResult(pdfBytes, "application/pdf") { FileDownloadName = "test.pdf" };
前端当前无法成功下载的代码:
$.ajax({ type: "POST", url: config.ExportUrl, contentType: "application/json", data: JSON.stringify(params), success: (response, status, error) => { this.isExporting = false; var defaultFileName = "test.pdf"; var blob = new Blob([response]); var blobUrl = window.URL.createObjectURL(blob); var anchor = document.createElement('a'); anchor.download = defaultFileName; anchor.href = blobUrl; document.body.appendChild(anchor); anchor.click(); document.body.removeChild(anchor); return response.content; }, });
解决方案
问题核心是:ajax默认会把响应解析为字符串,而PDF是二进制数据,字符串转Blob会导致数据损坏。需要调整请求配置,让响应以二进制形式接收。
修改后的前端代码
$.ajax({ type: "POST", url: config.ExportUrl, contentType: "application/json", data: JSON.stringify(params), responseType: 'blob', // 关键:指定响应为二进制Blob类型 success: (response, status, xhr) => { this.isExporting = false; // 可选:从响应头获取后端设置的文件名 var contentDisposition = xhr.getResponseHeader('Content-Disposition'); var defaultFileName = "test.pdf"; if (contentDisposition) { var filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/); if (filenameMatch?.[1]) { defaultFileName = filenameMatch[1].replace(/['"]/g, ''); } } var blobUrl = window.URL.createObjectURL(response); // 直接使用已返回的Blob var anchor = document.createElement('a'); anchor.download = defaultFileName; anchor.href = blobUrl; document.body.appendChild(anchor); anchor.click(); document.body.removeChild(anchor); window.URL.revokeObjectURL(blobUrl); // 释放Blob URL资源,避免内存泄漏 }, error: () => { this.isExporting = false; // 此处添加错误提示逻辑 } });
关键修改点说明
- 添加
responseType: 'blob':强制ajax不解析响应,直接返回二进制Blob对象,避免PDF数据因字符串解析损坏。 - 直接使用响应作为Blob:无需再手动创建Blob,因为response已经是正确的Blob类型。
- 从响应头获取文件名:可以自动匹配后端设置的
FileDownloadName,无需前端硬编码。 - 释放Blob URL资源:调用
revokeObjectURL清理内存,避免长期运行内存泄漏。
内容的提问来源于stack exchange,提问作者Angelo
相关产品推荐
相关产品推荐

