你的问题有两部分。首先是获取所有文件的问题,其次是下载它们的问题。在解决这些问题之前,让我们退后一步,了解请求-响应周期是如何工作的。
使用 HTTP,客户端发出请求,服务器返回响应。重要的是,这里存在精确的 1-1 相关性。一个请求只能有一个响应。这意味着,如果您需要提供多个文件下载,您have将它们压缩,因为您只能返回一个文件,而不能返回多个文件。创建 zip 文件允许您仅返回一个文件,同时仍然满足允许用户一次下载所有文件的要求。
然后就是AJAX的问题。这XMLHttpRequest
JavaScript 中的对象本质上是一个瘦客户端。它发出 HTTP 请求并接收响应,仅此而已。与通过地址栏导航时 Web 浏览器发出的请求不同,不会自动对响应执行任何操作,而是由您作为开发人员来处理响应并实际执行某些操作。
解决这个问题后,第一部分是创建一个可以返回 zip 文件作为响应的操作。这实际上非常简单:你只需要返回一个FileResult
:
[HttpPost]
public ActionResult DownloadCodes(List<int> codes)
{
// use codes to get the appropriate files, however you do that
using (var ms = new MemoryStream())
using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
foreach (var file in files)
{
// write zip archive entries
}
return File(ms.ToArray(), "application/zip");
}
}
对于 zip 存档条目的写入,这取决于文件数据的来源。如果您有文件系统引用,您只需执行以下操作:
zip.CreateEntryFromFile(file, Path.GetFileName(file));
如果您有字节数组,例如从数据库中的 varbinary 列返回的内容:
var entry = zip.CreateEntry(file.Name);
using (var fileStream = new MemoryStream(file.Data))
using (var entryStream = entry.Open())
{
fileStream.CopyTo(entryStream);
}
Where file.Name
and file.Data
由属性组成,分别指存储文件名的位置和存储文件数据的位置。
现在,您可以简单地对此操作执行普通表单发布,并且由于响应是在 Web 浏览器中无法查看的文件类型(zip 存档),因此浏览器将自动提示下载。此外,由于这在浏览器中不可见,因此选项卡/窗口中的实际视图也不会改变,从而消除了使用 AJAX 来完成停留在同一页面上的正常需要。但是,如果需要,您可以使用 AJAX,但您只能在现代浏览器(基本上除了 IE 10 或更低版本之外)中处理 AJAX 中的文件响应。如果您不需要支持旧版本的 IE,那么您需要的代码将类似于:
jQuery
$.ajax({
url: '/url/to/download/code/action',
data: data // where `data` is what you're posting, i.e. the list of codes
xhrFields: {
responseType: 'blob'
},
success: function (data) {
// handle file download
}
});
纯 JavaScript
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function () {
var data = xhr.response;
// handle file download
}
xhr.open('POST', '/url/to/download/codes/action');
xhr.send();
无论您选择哪条路径,处理文件下载的代码都是:
var a = document.createElement('a');
var url = window.URL.createObjectURL(data);
a.href = url;
a.download = 'myfile.pdf';
a.click();
window.URL.revokeObjectURL(url);