使用Javascript文件API保存文件会导致错误编码

使用Javascript文件API保存文件会导致错误编码,javascript,asp.net-web-api,encoding,download,fileapi,Javascript,Asp.net Web Api,Encoding,Download,Fileapi,我在使用HTML5文件API保存文件时遇到了一个问题(可能有两个) 一个文件以字节数组的形式来自服务器,我需要保存它。我尝试了上面描述的几种方法: 创建blob并在新选项卡中打开它 在href属性中添加带有“data:”的隐藏achor标记 使用FileSaver.js 所有方法都允许保存文件,但在文件(在当前测试用例中)为ANSI时,通过将编码更改为UTF-8来中断文件。似乎我必须解决一些问题:在服务器端和客户端 服务器端: 服务器端是ASP.NET Web API 2应用程序,控制器使用

我在使用HTML5文件API保存文件时遇到了一个问题(可能有两个)

一个文件以字节数组的形式来自服务器,我需要保存它。我尝试了上面描述的几种方法:

  • 创建blob并在新选项卡中打开它
  • 在href属性中添加带有“data:”的隐藏achor标记
  • 使用FileSaver.js
所有方法都允许保存文件,但在文件(在当前测试用例中)为ANSI时,通过将编码更改为UTF-8来中断文件。似乎我必须解决一些问题:在服务器端和客户端

服务器端: 服务器端是ASP.NET Web API 2应用程序,控制器使用带有StreamContent的HttpResponseMessage发送文件。ContentType是正确的,并且与实际的文件类型相对应

但正如下面的屏幕截图所示,服务器的答案(data.length)小于上传时计算的实际文件大小(file.size)。这里还可以看到HTML5文件对象还有另一个大小(f.size)

如果我将值为“ANSI”的字符集添加到服务器的响应消息的ContentType属性中,则文件数据将与上载的数据相同,但在保存结果文件时,文件大小仍然错误,并且已损坏:

客户端: 我尝试使用JS文件选项设置字符集,但没有帮助。正如我们可以找到的,FileUplaod.js的作者Eli Grey说

类型中的编码/字符集只是浏览器的元数据,而不是编码指令

这意味着,如果我理解正确,就不可能更改文件的编码

问题结果:最后我可以成功下载无法打开的损坏文件。

所以我有两个问题:

  • 如何使用文件API按原样保存文件。目前我无法使用直接链接和“下载”属性的简单方法,因为服务器端检查请求头中的访问令牌。这可能是问题的“瓶颈”吗
  • 如何避免在服务器端设置字符集,并按原样发送字节数组?虽然这个问题可以通过某种方式解决,但我想它更为关键。例如,虽然“ANSI”字符集解决了当前文件的问题,但WinMerge显示它的编码是西里尔字母“Windows-1251”,也可以是任何其他字符集
  • 另外,该问题与除*.txt以外的所有文件类型(扩展名)有关

    更新

    服务器端代码:

    public HttpResponseMessage DownloadAttachment(Guid fileId)
    {
        var stream = GetFileStream(fileId);
    
        var message = new HttpResponseMessage(HttpStatusCode.OK);
        message.Content = new StreamContent(stream);
        message.Content.Headers.ContentLength = file.Size;
        message.Content.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType)
            {
                // without this charset files sent with bigger size
                // than they are as shown on image 1
                CharSet = "ANSI"
            };
        message.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = file.FileName + file.Extension,
                Size = file.Size
            };
    
        return message;
    }
    
    客户端代码(TypeScript):

    /*
    *下载标记上单击事件的处理程序
    */
    私有下载文件(文件:Models.file){
    var self=这个;
    此.$service.downloadAttachment(this.entityId,file.fileId)。然后(
    //论成功
    函数(数据、状态、标题、配置){
    var fileName=file.fileName+file.extension;
    var clientFile=新文件([data],文件名);
    //问题就在这里---^
    saveAs(clientFile,文件名);
    },
    //失败时
    函数(错误){
    自我提醒错误(error);
    });
    }
    

    我的代码与关于SO的相关问题的答案几乎相同:我没有在“a”标记中设置直接链接,而是处理单击它并通过XHR下载文件内容(在我的例子中使用Angularjs$http服务)。获取文件内容时,我创建一个Blob对象(在我的示例中,我使用从Blob派生的file类),然后尝试使用FileSaver.js保存它。我还尝试了在href属性中使用编码URL到Blob的方法,但它只会打开一个新选项卡,其中一个文件以相同的方式断开。我发现probem在Blob类中——用“普通”文件数据调用它的构造函数,我得到了一个大小“错误”的实例,这在前两张sceenshot上可以看到。因此,据我所知,我的问题不在于我试图保存文件的方式,而在于我创建文件的方式——文件API是
    数据
    一个
    数组缓冲区
    或二进制字符串?@guest271314老实说,我不知道,但我想这是一个二进制字符串“我如何保存文件”“使用文件API。目前我无法使用直接链接和“下载”属性的简单方法,因为服务器端检查请求头中的访问令牌。“请参见您是否可以在问题?中包含
    js
    使用的文本和服务器端程序,而不是图片或图片下方?@guest271314谢谢您的关注。我用代码示例更新了这个问题。我还检查了
    数据
    -它的类型为
    字符串
    “因此,据我所知,我的问题不在于我试图保存文件的方式,而在于我创建文件的方式-文件API”您发布了您正在创建下载的
    .txt
    文件,但您描述了下载后损坏的图像文件吗?“问题结果:最终我可以成功下载无法打开的损坏文件。”为什么您试图在图像文件上设置字符编码stackoverflow.com/questions/701882/what-is-ansi-format?或者,如果您只创建了
    .txt
    文件供下载,为什么要包含损坏图像下载的说明?在
    新文件([数据],文件名)中,什么是
    数据
    /*
    * Handler for click event on download <a> tag
    */
    private downloadFile(file: Models.File) {
        var self = this;
    
        this.$service.downloadAttachment(this.entityId, file.fileId).then(
            // on success
            function (data, status, headers, config) {
                var fileName = file.fileName + file.extension;
                var clientFile = new File([data], fileName);
                // here's the issue ---^
                saveAs(clientFile, fileName);
            },
            // on fail
            function (error) {
                self.alertError(error);
        });
    }