Angular前端处理.Net API返回FormFile响应的问题
问题描述
后端.Net API同时返回file文件对象和status状态对象,但前端接收时file被转换为普通JSON对象,无法正常下载。尝试设置responseType: 'blob'后,不仅问题未解决,还丢失了status返回值。需求是让API返回的FormFile在前端TypeScript中转为File类型,支持保存、下载、展示等操作。
后端相关代码
GetFormFile方法
private FormFile getFormFile(string FileName, string url) { var client = new HttpClient(); var request = new HttpRequestMessage(HttpMethod.Get, url); request.Headers.Add("accept", "*/*"); var res = client.SendAsync(request).Result; var readResponse = res.Content.ReadAsByteArrayAsync().Result; var stream = new MemoryStream(readResponse); var file = new FormFile(stream, 0, readResponse.Length, "name", FileName) { Headers = new HeaderDictionary(), ContentType = "application/pdf" }; return file ; }
FileVal接口实现
public IActionResult FileVal() { Dictionary<string, object> objDictionary = new Dictionary<string, object>(); try { var form = Request.Form; var filesData = Request.Form.ToList(); var SrNo= Request.Form["SrNo"].ToString(); foreach (var formFile in form.Files) { var res = filesRepo.ValidateFile(formFile, SrNo); if (res.data["StatusCode"].ToString() == "Success") { return Ok(res); } } objDictionary.Add("Response", "No Files present"); _response.Status = 0; _response.Message = "Success"; _response.Data = objDictionary; return Ok(_response); } catch (Exception exception) { _logger.Error(exception.ToString()); objDictionary.Add("Response", exception.Message); _response.Status = 1; _response.Message = "error"; _response.Data = objDictionary; return Ok(_response); } }
API返回示例
{ "data": { "Status": [ { "message": "Validation Failed ", "result": "error", "filename": "VerifiedATL_File.pdf" } ], "StatusCode": "Success Call" }, "file": { "contentType": "application/pdf", "headers": { "Content-Type": [ "application/pdf" ] }, "length": 251147, "name": "name", "fileName": "VerifiedATL_File.pdf" } }
前端代码
this.https.post(`${this.VALIDATE_File}`, formData) .subscribe(res => { console.log('Result - ', res); var statuses = res['data']['Status']; let filess = res['file']; const file = new File([filess], statuses[0].filename); console.log(typeof filess); this.filesArray[sub1.Dropzonecode] = file; this.statusArray[sub1.Dropzonecode] = statuses[0]; // const link = document.createElement('a'); // link.href = URL.createObjectURL(blob); // link.download = statuses[0].filename; // document.body.append(link); // link.click(); // link.remove(); });
解决方案
核心问题
当前后端把FormFile直接序列化为JSON返回,仅保留了文件元数据,丢失了关键的二进制内容,导致前端无法还原出有效文件。
后端调整方案(二选一)
方案1:拆分两个接口
- 第一个接口:返回文件验证状态信息(无文件二进制)
- 第二个接口:根据状态中的标识(如文件名/文件ID)单独返回文件二进制流,前端调用时设置
responseType: 'blob'即可获取有效Blob。
方案2:单接口混合返回(状态放响应头,文件放响应体)
修改后端代码,将状态信息存入响应头,文件二进制作为响应体返回:
public IActionResult FileVal() { try { var form = Request.Form; var SrNo= Request.Form["SrNo"].ToString(); foreach (var formFile in form.Files) { var res = filesRepo.ValidateFile(formFile, SrNo); if (res.data["StatusCode"].ToString() == "Success") { // 将状态信息序列化后存入自定义响应头 Response.Headers.Add("X-Status-Data", System.Text.Json.JsonSerializer.Serialize(res.data)); // 返回文件流 var targetFile = res.file as FormFile; return File(targetFile.OpenReadStream(), targetFile.ContentType, targetFile.FileName); } } // 无文件场景返回状态JSON _response.Status = 0; _response.Message = "Success"; _response.Data = new Dictionary<string, object>{{"Response", "No Files present"}}; return Ok(_response); } catch (Exception exception) { _logger.Error(exception.ToString()); _response.Status = 1; _response.Message = "error"; _response.Data = new Dictionary<string, object>{{"Response", exception.Message}}; return Ok(_response); } }
注意:跨域场景下,后端需在CORS配置中添加
Access-Control-Expose-Headers: X-Status-Data,否则前端无法读取自定义响应头。
前端对应调整(适配方案2)
this.https.post(`${this.VALIDATE_File}`, formData, { responseType: 'blob', observe: 'response' // 需设置此参数才能获取完整响应头 }) .subscribe(response => { // 从响应头读取状态信息 const statusDataStr = response.headers.get('X-Status-Data'); let statuses = []; if (statusDataStr) { const statusData = JSON.parse(statusDataStr); statuses = statusData.Status; } // 将Blob转换为File并处理 const blob = response.body; if (blob && statuses.length > 0) { const file = new File([blob], statuses[0].filename, { type: 'application/pdf' }); this.filesArray[sub1.Dropzonecode] = file; this.statusArray[sub1.Dropzonecode] = statuses[0]; // 下载示例 const link = document.createElement('a'); link.href = URL.createObjectURL(file); link.download = statuses[0].filename; document.body.append(link); link.click(); link.remove(); URL.revokeObjectURL(link.href); // 释放内存 } });
内容的提问来源于stack exchange,提问作者Tony
相关产品推荐
相关产品推荐

