Angular 5调用C# Web API下载Docx文件异常求助
C# Model
public class docxModel { public byte[] testDocx { get; set; } }
C# Web API 文件返回方法代码
byte[] tDocx = File.Exists(wordFilePath) ? File.ReadAllBytes(wordFilePath):null; docxModel.testDocx = tDocx; return docxModel;
Angular Model
export interface ITestDocxModel { testDocx: Blob; }
Angular 服务
包含CreateWordDoc方法,用于调用Web API并映射上述C#模型至Angular模型。
Angular 组件代码
async printToWord() { await this.testService.CreateWordDoc() .then((res: ITestDocxModel) => { this.testModel = res; this.testDocx = this.testModel.testDocx; var testBlob = new Blob([this.testDocx], { type: 'text/docx' }); var url = window.URL.createObjectURL(testBlob); window.open(url); }) .catch(err => { this.handleError(err); }); }
问题:点击按钮调用
printToWord方法时,新窗口显示二进制数据,期望实现打开Word文档并提供保存选项的功能,恳请技术帮助。
这个问题出在几个关键环节:API返回数据的包装方式错误、Blob的MIME类型配置不对,以及缺少触发浏览器正确识别文档的逻辑。我来一步步帮你修正:
1. 重构Web API的返回逻辑(核心修复)
你现在把byte[]包装在模型里返回,会导致Angular接收到的是序列化后的JSON数据,而非原始的文件二进制流。正确的做法是让API直接返回文件流:
[HttpGet] public IActionResult GetWordDocument() { if (!File.Exists(wordFilePath)) { return NotFound(); } var fileBytes = File.ReadAllBytes(wordFilePath); // 指定正确的docx文件MIME类型和默认文件名 return File( fileBytes, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "test-document.docx" ); }
这样API会直接返回可被浏览器识别的Word文档流,同时告诉浏览器文件类型和默认保存名称。
2. 调整Angular服务的请求配置
因为API现在返回的是Blob流,服务里必须明确指定响应类型为blob,不能用默认的JSON解析:
import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class TestService { constructor(private http: HttpClient) { } CreateWordDoc() { // 关键:设置responseType为'blob' return this.http.get('/api/your-endpoint-path', { responseType: 'blob' }); } }
3. 修改组件的文档触发逻辑
直接用window.open容易因为浏览器安全策略或MIME类型问题失效,我们改用创建临时a标签的方式触发下载/打开:
async printToWord() { try { const blob = await this.testService.CreateWordDoc().toPromise(); // 创建临时a标签 const downloadLink = document.createElement('a'); const objectUrl = window.URL.createObjectURL(blob); downloadLink.href = objectUrl; // 设置下载文件名(可与API返回的一致,也可自定义) downloadLink.download = 'test-document.docx'; // 触发点击并清理资源 document.body.appendChild(downloadLink); downloadLink.click(); window.URL.revokeObjectURL(objectUrl); document.body.removeChild(downloadLink); } catch (err) { this.handleError(err); } }
另外提一句:你之前写的text/docx是错误的MIME类型,正确的docx类型是application/vnd.openxmlformats-officedocument.wordprocessingml.document,不过现在我们直接用API返回的Blob,不需要手动指定类型了。
为什么原来的方式失效?
原来的API把byte[]包装在JSON模型里,Angular接收到的testDocx并不是真正的Blob,而是被JSON序列化后的二进制数据(比如数组或Base64字符串),再包装成Blob后已经不是合法的Word文档流,所以浏览器只能显示乱码的二进制内容。
内容的提问来源于stack exchange,提问作者Shankar Naru

