前端下载由C#后端生成的ANSI压缩文件

3
我有一个使用C#编写的后端,可以在内存中生成一个zip文件(使用System.IO.Compression),并将其发送到前端。如果在发送之前下载zip文件,则可以正常工作并且是ANSI编码(在notepad++中找到)。
目前我返回文件的方式如下,我尝试了许多不同的方法来实现,例如仅返回无头文件,但现在它看起来像这样:
[HttpPost]
[Route("GetUserWorkContext")]
public async Task<IActionResult> GetUserWorkContext([FromBody] GetUserWorkContextRequest request, [FromServices] IExportManager exportManager)
{
    var zipStream = await exportManager.GetUserWorkContext(userId, request.IncludeArchived);
    HttpContext.Response.Headers.Add("Content-Disposition", "attachment; filename = test.zip; charset=Windows-1252");
    HttpContext.Response.Headers.Add("Content-Length", zipStream.ToArray().Length.ToString());
    return File(zipStream.ToArray(), "application/octet-stream");
}


无论我如何使用Javascript(前端)下载文件,似乎都是以utf8编码保存的(再次使用notepad++发现)。我试过使用js-file-download(https://www.npmjs.com/package/js-file-download)或创建blobs,但所有我下载的东西最终都是以utf8编码。
我应该如何在Javascript中下载此文件而不会破坏存档?
以下是我目前在Javascript中的尝试,使用我在这里找到的一段代码(JavaScript blob filename without link)来下载文件:
function getUserWorkContext({ includeArchived }) {
    return new Promise(function () {
        Axios.post('/api/Export/GetUserWorkContext', {includeArchived})
            .then((response) => {
                if(response.data){
                    var blobObject = new Blob([response.data], {type: 'application/zip;charset=Windows-1252'});
                    downloadFile(blobObject, "test.zip");
                }
            })
}

function downloadFile(file, fileName) {
    if (navigator.msSaveBlob) { // For ie and Edge
        return navigator.msSaveBlob(file, fileName);
    }
    else {
        let link = document.createElement('a');
        link.href = window.URL.createObjectURL(file);
        link.download = fileName;
        document.body.appendChild(link);
        link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
        link.remove();
        window.URL.revokeObjectURL(link.href);
    }
}

注意:实际zip文件大小为3,747KB,而从JavaScript下载的zip文件始终要大得多,在这种情况下:6,917KB。

2
你尝试过移除Content-Disposition和Content-Length头吗?在我看来它们是多余的... - Eduard Keilholz
@nikneem 是的,我试过返回 return File(zipStream.ToArray(), "application/octet-stream"); 和 return File(zipStream.ToArray(), "application/octet-stream", "test.zip"); 没有设置头文件,两者都没有起作用。 - barbo
我相信,你不需要转换你的“zipStream.ToArray()”。它可以与流“File(zipStream, "application/octet-stream", "test.zip");”很好地配合使用。 - Tolbxela
不错的想法@Tolbxela,但似乎并没有改变结果。 - barbo
1
@barbo请检查我的更新答案。 - Tolbxela
1个回答

2

这是关于axios的一个问题:

我猜你应该使用blobarraybuffer作为axios的responseType

{ responseType: 'blob' }

// responseType指示服务器将响应的数据类型 // 可选项包括:'arraybuffer','document','json','text','stream' // 仅适用于浏览器:'blob'

responseType: 'json' // 默认值

查看这个答案:https://dev59.com/_lIH5IYBdhLWcg3wOrK7#60461828

=== 8< ======================= 之前的版本 ======================= 8< ===

你的Content-Disposition头是错误的。对于Content-Disposition头,没有charset参数。

请查看文档:MDN HTTP Content-Disposition

这就是为什么你的文件仍然以UTF-8格式发送的原因,因为你的charset参数没有起作用。

要使用UTF-8:

从C#中删除两个Content-头,并从JavaScript中删除charset参数。

var blobObject = new Blob([response.data], {type: 'application/zip'});

如果你确实需要使用 Windows-1252,你可以尝试使用内容类型参数进行设置。
 return File(zipStream.ToArray(), "application/octet-stream;charset=Windows-1252");

请查看这个链接:ASP.NET响应中的字符集编码
另外,UTF-8是首选的字符集编码方式,请参考W3如何选择编码方式
还有,@nikneem,不需要使用Content-DispositionContent-Length头部信息,系统会自动生成。

1
嗨!内容类型不会改变结果。我认为问题更多地在于前端下载文件的方式,因为它总是默认为utf8。用于创建blob的response.data只是一个字符串,没有关于使用的内容类型的信息... - barbo
1
你不需要将你的存档编码为UTF8。只需从js中删除charset参数即可var blobObject = new Blob([response.data], {type: 'application/zip'}); - Tolbxela
1
在“filename*=UTF-8”test.zip中,“UTF-8”是文件名的编码,而不是zip归档的编码! - Tolbxela
好的,我会尝试一下。另外我注意到在我的响应头中有这个: X-SourceFiles: =?UTF-8?B?QzpcX1Byb2pldHNcTGV4Um9ja19Bbm5vdGF0aW9uXGFwcHNcTGV4Um9jay5XZWIuQXBwXGFwaVxFeHBvcnRcR2V0VXNlcldvcmtDb250ZXh0?= 这也可能导致潜在问题吗? - barbo
1
不用理会我之前的问题了,添加responseType解决了所有问题!非常感谢你! - barbo
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接