You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过XMLHttpRequest从JSON获取文件后无法打开的问题排查

问题:通过XMLHttpRequest获取JSON接口返回的文件后无法正常打开

尝试通过XMLHttpRequest从JSON接口获取文件,下载后的文件无法正常打开。数据库中存储的文件本身无异常(在C#中可正常保存并打开),问题仅出在JavaScript接收文件的环节。

前端JavaScript代码

var xmlHttpRequest = new XMLHttpRequest();
if (!window.XMLHttpRequest) {
   xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}

let formData = new FormData();
formData.append('request.Id', window.$(this).attr('data'));
xmlHttpRequest.open("POST", 'Url', true);

xmlHttpRequest.onloadend = function () {
        let response = ParseJson(xmlHttpRequest.responseText);

        alert(response.Result);

        let blob = new Blob([response.File], { type: response.MimeType }); 

        let a = document.createElement('a');
        a.href = window.URL.createObjectURL(blob);

        a.download = response.FileName;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        window.URL.revokeObjectURL(a.href);
}
xmlHttpRequest.send(formData);

后端C# Controller代码

public IActionResult GetFileDownload(GetFileDownloadRequest request)
{
       //Get byte[] from database

       return Json(new GetFileDownload()
       {
              Result = "OK",
              FileName = file.Name ?? "",
              MimeType = Path.GetExtension(file.Name).GetMimeType(),
              File = file.File
       });
}

问题原因及解决方案

核心问题

后端返回JSON时,byte[]类型的File会被自动序列化为Base64字符串。而前端直接将这个字符串作为字节内容创建Blob,导致文件实际存储的是Base64文本,而非原始二进制数据,因此无法正常打开。

方案一:前端解码Base64字符串(无需修改后端)

修改前端onloadend中的Blob创建逻辑,将Base64字符串解码为原始字节数组:

xmlHttpRequest.onloadend = function () {
        let response = ParseJson(xmlHttpRequest.responseText);

        alert(response.Result);

        // 解码Base64字符串为Uint8Array
        const byteCharacters = atob(response.File);
        const byteNumbers = new Array(byteCharacters.length);
        for (let i = 0; i < byteCharacters.length; i++) {
            byteNumbers[i] = byteCharacters.charCodeAt(i);
        }
        const byteArray = new Uint8Array(byteNumbers);

        let blob = new Blob([byteArray], { type: response.MimeType }); 

        let a = document.createElement('a');
        a.href = window.URL.createObjectURL(blob);

        a.download = response.FileName;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        window.URL.revokeObjectURL(a.href);
}

方案二:后端直接返回文件流(更高效,推荐)

如果不需要同时返回其他JSON数据,可以修改后端直接返回文件流,前端直接接收Blob:

修改后端代码

public IActionResult GetFileDownload(GetFileDownloadRequest request)
{
       //Get byte[] from database

       // 直接返回文件流,自动处理MIME类型和文件名
       return File(file.File, file.MimeType, file.Name);
}

修改前端代码

var xmlHttpRequest = new XMLHttpRequest();
if (!window.XMLHttpRequest) {
   xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}

let formData = new FormData();
formData.append('request.Id', window.$(this).attr('data'));
xmlHttpRequest.open("POST", 'Url', true);

// 设置响应类型为blob
xmlHttpRequest.responseType = 'blob';

xmlHttpRequest.onloadend = function () {
        // 直接获取Blob对象
        let blob = xmlHttpRequest.response;

        let a = document.createElement('a');
        a.href = window.URL.createObjectURL(blob);

        // 从响应头解析文件名(后端返回File时自动设置Content-Disposition)
        const contentDisposition = xmlHttpRequest.getResponseHeader('Content-Disposition');
        let fileName = '';
        if (contentDisposition) {
            const matches = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
            if (matches != null && matches[1]) {
                fileName = decodeURIComponent(matches[1].replace(/['"]/g, ''));
            }
        }
        a.download = fileName || response.FileName;
        
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        window.URL.revokeObjectURL(a.href);
}
xmlHttpRequest.send(formData);

内容的提问来源于stack exchange,提问作者Mohamad Hasan Salmaaniyaan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 19:13:30