ASP.NET Core内存生成ZIP并随结果对象返回至JS客户端方案
问题描述
ASP.NET Core应用中,表单提交至控制器后生成1个或多个物理文件,打包为ZIP后需返回包含处理状态、完成数量、归档下载信息的对象。但生成的ZIP不在Web根目录无法直接下载,且临时文件需后续清理,希望改为内存中生成ZIP,同时返回处理信息、ZIP二进制内容及下载文件名,实现前端直接下载。
解决方案
一、后端修改(ASP.NET Core)
1. 更新ViewModel类
修改UpdateResultsVM,添加存储ZIP二进制数据的属性,保留文件名用于前端下载命名:
public class UpdateResultsVM { public int ClaimUpdateReturn { get; set; } public string ClaimUpdateMsg { get; set; } public string ZipFileName { get; set; } // 仅存储ZIP文件名,用于前端下载 public byte[] ZipContent { get; set; } // 内存中的ZIP二进制数据 public bool Completed { get; set; } public string Message { get; set; } }
2. 重构ZIP生成方法(内存版)
将原物理文件生成ZIP的逻辑改为在内存中生成,返回文件名和二进制内容:
public (string ZipFileName, byte[] ZipContent) CreateZipFile(string tagName, List<string> Documents) { try { // 生成唯一ZIP文件名 string zipFileName = (string.IsNullOrEmpty(tagName) ? "Zip_" : tagName + "_") + DateTimeOffset.Now.ToString("yyyyMMddHHmmssffff") + ".zip"; using (var memoryStream = new MemoryStream()) { // 创建内存中的ZipArchive,leaveOpen设为true避免提前关闭流 using (ZipArchive zip = new ZipArchive(memoryStream, ZipArchiveMode.Create, leaveOpen: true)) { foreach (string document in Documents) { // 将物理文件添加到内存ZIP中,原文件保留 zip.CreateEntryFromFile(document, Path.GetFileName(document)); } } // 将内存流转为字节数组返回 return (zipFileName, memoryStream.ToArray()); } } catch (Exception ex) { // 自定义异常处理逻辑(如记录日志) throw; } }
3. 控制器方法组装返回对象
在PerformProcess方法中执行处理逻辑,调用内存ZIP生成方法,填充ViewModel并返回JSON:
[HttpPost] public IActionResult PerformProcess(int[] IDs, int LetterID) { var resultsVM = new UpdateResultsVM(); try { // 执行原有业务逻辑,获取生成的物理文件路径列表 List<string> generatedDocuments = GetProcessedDocuments(IDs, LetterID); // 生成内存ZIP var (zipName, zipBytes) = CreateZipFile("ProcessedFiles", generatedDocuments); // 填充返回结果 resultsVM.ClaimUpdateReturn = 1; resultsVM.Completed = true; resultsVM.ZipFileName = zipName; resultsVM.ZipContent = zipBytes; resultsVM.Message = "处理完成"; } catch (Exception ex) { resultsVM.ClaimUpdateReturn = 0; resultsVM.Completed = false; resultsVM.Message = $"处理失败: {ex.Message}"; } return Json(resultsVM); }
二、前端JavaScript修改
将后端返回的Base64编码ZIP内容转为Blob,生成下载链接触发浏览器下载:
$.ajax({ type: "POST", url: "/Work/PerformProcess", data: { IDs: IDs, LetterID: LetterID }, dataType: "json", success: function (result) { // 保留原有Promise逻辑(如果需要) // d.resolve(result); if (result.ClaimUpdateReturn === 0) { console.error("处理错误:", result.Message); // 自定义错误提示逻辑 } else if (result.ClaimUpdateReturn === 1) { if (result.Completed && result.ZipContent) { // 将Base64字符串解码为字节数组 const byteChars = atob(result.ZipContent); const byteNumbers = new Array(byteChars.length); for (let i = 0; i < byteChars.length; i++) { byteNumbers[i] = byteChars.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); // 创建ZIP类型的Blob对象 const zipBlob = new Blob([byteArray], { type: 'application/zip' }); // 生成临时下载链接 const downloadUrl = window.URL.createObjectURL(zipBlob); const a = document.createElement('a'); a.href = downloadUrl; a.download = result.ZipFileName; document.body.appendChild(a); a.click(); // 清理临时资源 window.URL.revokeObjectURL(downloadUrl); document.body.removeChild(a); console.log("ZIP文件下载完成"); } } else { // 其他状态处理逻辑 } }, error: function (response) { alert("请求出错: " + response.responseText); // d.resolve(response); } });
关键说明
- ASP.NET Core默认会将
byte[]序列化为Base64字符串,前端需用atob()解码为字节数组。 - 使用
Blob对象将二进制数据转为可下载的资源,application/zip是标准ZIP文件的MIME类型。 - 生成临时URL后需调用
revokeObjectURL清理资源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者nonesuch
相关产品推荐
相关产品推荐

