You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 23:15:32