在一个ASP.NET Core MVC的控制器中,根据条件,可能返回一个Excel的文件流,也可能返回一个Json的错误信息,代码类似如下:
if(templeteId == null)
{
return Json(new {success = false, msg = "没有指定模板"});
}
else
{
//生成文件流的代码略,stream是文件流,fileName是文件名
return File(stream.GetBuffer(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"{fileName}.xlsx");
}
在前端,我用jquery的ajax访问后台
$.ajax({
url: "@Url.Action("GenerateReport")",
data: {taskId: taskId, linePointId: linePointId},
dataType: "blob",
type: "get",
success: (result,status,xhr) => {
console.log(result)
},
error: (xhr,status,error) => {
console.log(error)
}
})
不管是返回json还是文件流,控制台的输出都是No conversion from text to blob
。
我一度以为是我的后台问题,我甚至把返回Json的代码改成这样:
var json = "{\"success\": false, \"msg\": \"没有模板文件\"}";
return File(Encoding.UTF8.GetBytes(json), "text/plain");
结果还是一样。
我把前端代码中的dataType: "blob"
删掉,调用倒是没问题了,但不管是文件流还是json,返回的形式都变成了Text。
我在ajax函数的success回调中打印xhr对象,才发现jquery封装的这个xhr对象,只提供了responseText
属性,而原始的XMLHttpRequest
中的response
属性并没有提供给我们。
百度了一下,发现网上成功处理我这种后台返回类型的都是用的axios,但我并不想因为一个ajax的调用又引入一个js库。
最终只能用XMLHttpRequest
对象完成。
function exportReport(taskId, linePointId){
var xhr = new XMLHttpRequest();
xhr.open("get", `@Url.Action("GenerateReport")?taskId=${taskId}&linePointId=${linePointId}`, true);
xhr.responseType = "blob";
xhr.onreadystatechange = () => {
if(xhr.readyState == 4 && xhr.status == 200) {
let contentType = xhr.getResponseHeader("content-type");
let blob = new Blob([xhr.response]);
if(contentType.includes("application/json")) {
blob.text().then(text => {
let json = JSON.parse(text);
layer.msg(json.msg);
});
} else {
let disposition = xhr.getResponseHeader("content-disposition");
let fileName;
if(disposition.includes("filename*")) {
//如果包含filename*,则以该字段内容为文件名,并对文件名进行解码
fileName = disposition.split(';')[2].split('=')[1];
fileName = fileName.substring(fileName.lastIndexOf("'") + 1);
fileName = urlDecode(fileName);
} else {
fileName = disposition.split(';')[1].split('=')[1];
}
let url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
}
}
}
xhr.send();
}