我正在尝试提供一个zip存档,以响应从Axios到WebAPI的AJAX POST请求。
在客户端我有
import AjaxDownload from "../../data/AjaxDownload";
AjaxDownload.post(id, pageRecords, {
responseType: "blob"
}).then((response) => {
let blob = new Blob([response.data], { type: extractContentType(response) }),
url = window.URL.createObjectURL(blob);
window.open(url, "_self");
}).catch((error) => {
// ...
}).then(() => {
// ...
});
function extractContentType(response: AxiosResponse): string {
return response.headers["content-type"] || "";
}
// AjaxDownload:
import * as axios from "axios";
import { apiUrl } from "./Ajax";
const ajax = axios.default.create({
baseURL: new URL("download", apiUrl).toString(),
timeout: 3600000 // 1 hour
});
export default ajax;
发布到以下WebAPI方法 - 该客户端逻辑的POST部分完全按预期工作。
[HttpPost]
[Route("download/{id:guid}")]
public async Task<HttpResponseMessage> Download(Guid id, [FromBody] IEnumerable<PageRecord> pageRecords)
{
var stream = await _repo.GetAsArchiveStream(id,
pageRecords,
true).ConfigureAwait(false);
stream.Position = 0;
var result = new HttpResponseMessage(HttpStatusCode.OK) {Content = new StreamContent(stream)};
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {FileName = $"{...}.zip"};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); // "application/zip" has same result
result.Content.Headers.ContentLength = stream.Length;
return result;
}
但是,浏览器将result.Content
显示为JSON对象,而不包含zip存档。我假设它显示为JSON,因为请求提到了JSON,但为什么它似乎忽略了二进制内容 - 特别是当Content-Type标题详细说明内容的类型时?
正如您所看到的,JavaScript也期望将内容读作blob。
我不知道我的代码与this answer有何不同之处 - 请解释 是否存在重要差异。
在服务器端,我也尝试过返回...
return new FileStreamResult(stream, "application/zip");
这种方法的问题在于无法设置文件名。 Firefox确实下载了一个随机名称的zip,而Chrome似乎根本没有下载任何内容。
必须有办法做到这一点,对吧?要将请求发布到返回zip存档的WebAPI方法,然后客户端会显示保存对话框?我错过了什么?
答案 0 :(得分:0)
我设法通过使用...
从控制器操作返回zip来解决这个问题return File(stream,
"application/zip",
"FILENAME.zip");
在客户端代码中,我可以使用this SO answer中的一些JavaScript从标头中获取文件名。
let blob = new Blob([response.data], { type: extractContentType(response) }),
downloadUrl = window.URL.createObjectURL(blob),
filename = "",
disposition = response.headers["content-disposition"];
if (disposition && disposition.indexOf("attachment") !== -1) {
let filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/,
matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
filename = matches[1].replace(/['"]/g, '');
}
}
var a = document.createElement("a");
// safari doesn't support this yet
if (typeof a.download === 'undefined') {
window.location.href = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}