let xhr = new XMLHttpRequest();
xhr.open("post", opt.url, true);
xhr.responseType = "blob";
xhr.setRequestHeader("Authorization", "Bearer " + jwtString.JwtToken);
xhr.setRequestHeader('Content-type', 'application/json');
xhr.onerror = function () {
if (!!opt.showMsg)
opt.showMsg("Request Error");
};
xhr.onprogress = function (event) {
if (event.lengthComputable) {
console.debug(`Received ${event.loaded} of ${event.total} bytes`);
} else {
console.debug(`Received ${event.loaded} bytes`);
}
};
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
let type = xhr.getResponseHeader("content-type");
if (type == "text/plain") {
let blobresult = new Blob([xhr.response], { type: "text/plain" });
blobresult.text().then(text => {
if (!!opt.showMsg)
opt.showMsg(text);
});
return;
}
let blob = new Blob([xhr.response], { type: type });
// 从Response Headers中获取fileName-->中文会乱码?
let fileName = xhr.getResponseHeader('Content-Disposition').split(';')[1].split('=')[1].replace(/\"/g, '');
fileName = decodeURIComponent(fileName);
//对于<a>标签,只有 Firefox 和 Chrome(内核)支持 download 属性
//IE10以上支持blob,但是依然不支持download
if ('download' in document.createElement('a')) {
//支持a标签download的浏览器
//通过创建a标签实现
let link = document.createElement("a");
//文件名
link.download = fileName;
link.style.display = "none"
link.href = URL.createObjectURL(blob);
document.body.appendChild(link);
link.click();//执行下载
URL.revokeObjectURL(link.href);//释放url
document.body.removeChild(link);//释放标签
//success
if (!!opt.showMsg)
opt.showMsg(JSi18n["uSRM-DownComplete"]);
} else {
//不支持
if (window.navigator.msSaveOrOpenBlob)
window.navigator.msSaveOrOpenBlob(blob, fileName);
}
} else {
if (!!opt.showMsg)
opt.showMsg("Request Error.status=" + this.status);
}
}
};
xhr.send(JSON.stringify(opt.data));
后端
/// <summary>
/// 下载文件的格式化输出
/// </summary>
[Serializable]
public sealed class ResumeFileFilterAttribute : ActionFilterAttribute
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="order"></param>
public ResumeFileFilterAttribute(int order)
: base()
{
base.Order = order;
}
public override void OnResultExecuted(ResultExecutedContext context)
{
if (context.Exception != null)
context.HttpContext.Response.Headers[HeaderNames.ContentType] = "text/plain";
base.OnResultExecuted(context);
}
/// <summary>
/// 附加请求头
/// </summary>
/// <param name="context"></param>
public override void OnResultExecuting(ResultExecutingContext context)
{
if (context.Result is FileResult)
{
var fileResult = (context.Result as FileResult);
context.HttpContext.Response.Headers[HeaderNames.AccessControlExposeHeaders] = HeaderNames.ContentDisposition;
context.HttpContext.Response.Headers[HeaderNames.ContentType] = fileResult.ContentType;
context.HttpContext.Response.Headers[HeaderNames.ContentEncoding] = Encoding.UTF8.HeaderName;
context.HttpContext.Response.Headers[HeaderNames.ContentDisposition] = CreateDownfileName(context.HttpContext, fileResult.FileDownloadName);
}
else if (context.Result is EmptyResult)
context.Result = new JsonResult(L.Text["查无数据,无法导出该文件"].Value) { ContentType = "text/plain" };
base.OnResultExecuting(context);
}
private string CreateDownfileName(HttpContext httpContext, string fileName)
{
var detectionService = httpContext.RequestServices.GetService<IDetectionService>();
ContentDispositionHeaderValue attachmentHeaderValue = new("attachment");
if (detectionService.Browser.Name == Browser.InternetExplorer && (detectionService.Browser.Version == Version.Parse("7.0") || detectionService.Browser.Version == Version.Parse("8.0")))
attachmentHeaderValue.SetMimeFileName(HttpUtility.UrlEncode(fileName, Encoding.UTF8));
else if (detectionService.UserAgent != null && detectionService.UserAgent.ToLower().Contains("android"))
attachmentHeaderValue.SetMimeFileName(MakeAndroidSafeFileName(fileName));
else
attachmentHeaderValue.SetHttpFileName(HttpUtility.UrlEncode(fileName, Encoding.UTF8));
return attachmentHeaderValue.ToString();
}
private static readonly Dictionary<char, char> AndroidAllowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-+,@£$€!½§~'=()[]{}0123456789".ToDictionary(c => c);
private static string MakeAndroidSafeFileName(string fileName)
{
char[] newFileName = fileName.ToCharArray();
for (int i = 0; i < newFileName.Length; i++)
{
if (!AndroidAllowedChars.ContainsKey(newFileName[i]))
newFileName[i] = '_';
}
return new string(newFileName);
}
}