尝试使用AngularJS和C# WebAPI从服务器下载文件。

31 浏览
0 Comments

尝试使用AngularJS和C# WebAPI从服务器下载文件。

上传文件到服务器时非常顺利,没有损坏的文件。然而,当我下载文件时(除了纯文本文件外,它们正常工作),它们会变大并变得损坏。经过详细调查后,我不知道可能出了什么问题。我只是将文件作为流写入响应并下载blob。

欢迎任何想法!在解决方案中大量依赖于这个线程:Download file from an ASP.NET Web API method using AngularJS

以下是当前的代码;

WebApi:

    [Route("GetFile")]
public HttpResponseMessage GetFile()
{
    HttpResponseMessage result = null;
    //在这里获取文件对象
    try 
    {
        IEnumerable headerValues = Request.Headers.GetValues("fileID");
        int key = Int32.Parse(headerValues.FirstOrDefault());
        var fetchFile = db.FileRecords.Single(a => a.id == key);
        var localFilePath = fetchFile.path + fetchFile.name;
        if (!System.IO.File.Exists(localFilePath))
        {
            result = Request.CreateResponse(HttpStatusCode.Gone);
        }
        else
        {//向客户端提供文件
            //我使用x-filename头发送文件名。这是为了方便而自定义的头。
            //您还应设置响应的内容类型mime头,以便浏览器知道数据格式。
            var info = System.IO.File.GetAttributes(localFilePath);
            result = Request.CreateResponse(HttpStatusCode.OK);
            result.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
            result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            result.Content.Headers.Add("x-filename", fetchFile.name);
            result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
            result.Content.Headers.ContentDisposition.FileName = fetchFile.name;
        }
        return result;
    }
    catch (Exception e)
    {
        return Request.CreateResponse(HttpStatusCode.BadRequest);
    }
}

View:


Controller:

    /******** 文件下载  **********/
$scope.downloadFiles = function (file) {
        $http({
            method: 'GET',
            cache: false,
            url: host + 'api/Files/GetFile',
            headers: {
                'Content-Type': 'application/json; charset=utf-8',
                'fileID': file.id
            }
        }).success(function (data, status, headers) {
            var octetStreamMime = 'application/octet-stream';
            var success = false;
            //获取头部信息
            headers = headers();
            //从x-filename头获取文件名,如果没有默认为"download.bin"
            var filename = headers['x-filename'] || 'download.bin';
            //根据头部确定内容类型,如果没有默认为"application/octet-stream"
            var contentType = headers['content-type'] || octetStreamMime;
            try {
                console.log(filename);
                //如果支持,尝试使用msSaveBlob
                console.log("尝试使用saveBlob方法...");
                var blob = new Blob([data], { type: contentType });
                if (navigator.msSaveBlob)
                    navigator.msSaveBlob(blob, filename);
                else {
                    //如果可用,尝试使用其他saveBlob实现
                    var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob;
                    if (saveBlob === undefined) throw "不支持";
                    saveBlob(blob, filename);
                }
                console.log("saveBlob方法成功");
                success = true;
            } catch (ex) {
                console.log("saveBlob方法发生以下异常:");
                console.log(ex);
            }
            if (!success) {
                //获取blob的URL创建器
                var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL;
                if (urlCreator) {
                    //尝试使用下载链接
                    var link = document.createElement('a');
                    if ('download' in link) {
                        try {
                            console.log("尝试使用模拟点击的下载链接方法...");
                            var blob = new Blob([data], { type: contentType });
                            var url = urlCreator.createObjectURL(blob);
                            link.setAttribute('href', url);
                            //设置下载属性(在Chrome 14+ / Firefox 20+中受支持)
                            link.setAttribute("download", filename);
                            //模拟点击下载链接
                            var event = document.createEvent('MouseEvents');
                            event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
                            link.dispatchEvent(event);
                            console.log("使用模拟点击的下载链接方法成功");
                            success = true;
                        } catch (ex) {
                            console.log("使用模拟点击的下载链接方法发生以下异常:");
                            console.log(ex);
                        }
                    }
                    if (!success) {
                        //回退到window.location方法
                        try {
                            console.log("尝试使用window.location的下载链接方法...");
                            var blob = new Blob([data], { type: octetStreamMime });
                            var url = urlCreator.createObjectURL(blob);
                            window.location = url;
                            console.log("使用window.location的下载链接方法成功");
                            success = true;
                        } catch (ex) {
                            console.log("使用window.location的下载链接方法发生以下异常:");
                            console.log(ex);
                        }
                    }
                }
            }
            if (!success) {
                //回退到window.open方法
                console.log("没有方法可以保存数组缓冲区,使用最后的备选方案window.open");
                window.open(httpPath, '_blank', '');
            }
            /******************/
        }).error(function (data, status) {
            console.log("请求失败,状态为:" + status);
            //可选择将错误写入作用域
            //$scope.errorDetails = "请求失败,状态为:" + status;
        });
}

0
0 Comments

问题的原因是在下载文件时,文件会出现损坏并且字节数会比原始上传的文件多。解决方法是将响应类型(responseType)设为'arraybuffer'。

在GET请求中,将响应类型设置为'arraybuffer'后,浏览器能够正确解释文件。

以下是代码示例:

$scope.downloadFiles = function (file) {
    $http({
        method: 'GET',
        cache: false,
        url: host + 'api/Files/GetFile',
        responseType:'arraybuffer',
        headers: {
            'Content-Type': 'application/json; charset=utf-8',
            'fileID': file.id
        }
    });
};

感谢提供答案,我已经尝试了几天,但无法找到为什么我的下载文件会损坏并且字节数会比原始上传的文件多的原因。我按照你的解决方案实施了相同的解决方法,只是加了responseType: 'arraybuffer'。但是没有想到这可能是一个重要的问题。

0