如何从ASP.NET MVC控制器向Ajax请求返回多文档Zip包?
问题分析与解决方案
核心问题
- 前端请求格式错误:重复定义
dataType,数据格式与后端参数不匹配导致请求无法命中控制器;同时错误设置响应类型,无法正确处理Zip二进制文件。 - 控制器潜在问题:未处理文档列表为空的情况,缺少返回值;参数绑定可能因请求格式不匹配失败。
前端代码修正
var UserId = $('#downloadDocsUserId').val(); $.ajax({ url: "@Url.Action("DownloadMyDocuments", "Home")", type: 'POST', dataType: "blob", // 明确预期响应为二进制文件 data: JSON.stringify({ userId: UserId }), // 传递符合后端参数的JSON结构 processData: false, // 已手动转为JSON字符串,无需jQuery自动处理 contentType: "application/json; charset=utf-8", success: function (blobData) { // 手动创建下载链接触发文件保存 const url = window.URL.createObjectURL(blobData); const a = document.createElement('a'); a.href = url; a.download = "Documents.zip"; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); }, error: function (xhr) { console.log("请求错误", xhr.responseText); } });
修正点:
- 移除重复的
dataType定义,设置为blob以适配Zip二进制流 - 用
JSON.stringify包装参数为标准JSON结构,确保后端能正确绑定 - 关闭
processData,避免jQuery破坏JSON字符串格式 - 成功回调中添加二进制文件的下载逻辑,直接返回的blob无法被JSON解析,需手动触发下载
控制器代码修正
[HttpPost] public IActionResult DownloadMyDocuments([FromBody] int userId) { var myDocuments = _context.Documents.Where(x => x.UserId == userId).ToList(); if (!myDocuments.Any()) { return NotFound("未找到该用户的文档"); } using (var stream = new MemoryStream()) { using (var archive = new ZipArchive(stream, ZipArchiveMode.Create, true)) { foreach (var document in myDocuments) { if (System.IO.File.Exists(document.FullPath)) { byte[] fileBytes = System.IO.File.ReadAllBytes(document.FullPath); var archiveEntry = archive.CreateEntry(document.FileName, CompressionLevel.Fastest); using (var zipStream = archiveEntry.Open()) { zipStream.Write(fileBytes, 0, fileBytes.Length); } } } } stream.Position = 0; return File(stream.ToArray(), "application/zip", "Documents.zip"); } }
修正点:
- 参数添加
[FromBody]特性,明确从请求体JSON中绑定userId - 简化逻辑,直接查询文档列表(无需额外ViewModel)
- 添加空列表判断,返回
NotFound结果,避免无返回值的情况 - 移除无用的
contentType变量,最终返回固定的Zip类型MIME
可选方案(表单传参)
如果不想用JSON格式传参,可改为表单提交:
- 前端:设置
contentType: "application/x-www-form-urlencoded",data: { userId: UserId },移除JSON.stringify和processData: false - 控制器:移除
[FromBody]特性,保持int userId即可
内容的提问来源于stack exchange,提问作者SalarianEngineer
相关产品推荐
相关产品推荐

