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

7
上传文件到服务器时一切顺利,没有损坏的文件。然而,当我下载文件(除了纯文本文件外,它们能正常工作),它们会变得更大并且损坏。经过许多调查,我不知道可能出了什么问题。我只是将文件作为流写入响应并下载Blob。
欢迎任何想法!
强烈依赖此线程解决; Download file from an ASP.NET Web API method using AngularJS
以下是当前代码;
WebApi:
    [Route("GetFile")]
public HttpResponseMessage GetFile()
{
    HttpResponseMessage result = null;
    //Get file object here
    try 
    {
        IEnumerable<string> 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
        {// serve the file to the client
            //I have used the x-filename header to send the filename. This is a custom header for convenience.
            //You should set the content-type mime header for your response too, so the browser knows the data format.
            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);
    }
}

视图:

<button type="button" class="btn btn-default btn-sm" data-localize="DOWNLOAD" ng-click="downloadFiles(file)">
    Download file
</button>

控制器:

    /******** FILE DOWNLOAD  **********/
$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;

            // Get the headers
            headers = headers();

            // Get the filename from the x-filename header or default to "download.bin"
            var filename = headers['x-filename'] || 'download.bin';

            // Determine the content type from the header or default to "application/octet-stream"
            var contentType = headers['content-type'] || octetStreamMime;

            try {

                console.log(filename);
                // Try using msSaveBlob if supported
                console.log("Trying saveBlob method ...");
                var blob = new Blob([data], { type: contentType });
                if (navigator.msSaveBlob)
                    navigator.msSaveBlob(blob, filename);
                else {
                    // Try using other saveBlob implementations, if available
                    var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob;
                    if (saveBlob === undefined) throw "Not supported";
                    saveBlob(blob, filename);
                }
                console.log("saveBlob succeeded");
                success = true;
            } catch (ex) {
                console.log("saveBlob method failed with the following exception:");
                console.log(ex);
            }

            if (!success) {
                // Get the blob url creator
                var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL;
                if (urlCreator) {
                    // Try to use a download link
                    var link = document.createElement('a');
                    if ('download' in link) {
                        // Try to simulate a click
                        try {
                            // Prepare a blob URL
                            console.log("Trying download link method with simulated click ...");
                            var blob = new Blob([data], { type: contentType });
                            var url = urlCreator.createObjectURL(blob);
                            link.setAttribute('href', url);

                            // Set the download attribute (Supported in Chrome 14+ / Firefox 20+)
                            link.setAttribute("download", filename);

                            // Simulate clicking the download link
                            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("Download link method with simulated click succeeded");
                            success = true;

                        } catch (ex) {
                            console.log("Download link method with simulated click failed with the following exception:");
                            console.log(ex);
                        }
                    }

                    if (!success) {
                        // Fallback to window.location method
                        try {
                            // Prepare a blob URL
                            // Use application/octet-stream when using window.location to force download
                            console.log("Trying download link method with window.location ...");
                            var blob = new Blob([data], { type: octetStreamMime });
                            var url = urlCreator.createObjectURL(blob);
                            window.location = url;
                            console.log("Download link method with window.location succeeded");
                            success = true;
                        } catch (ex) {
                            console.log("Download link method with window.location failed with the following exception:");
                            console.log(ex);
                        }
                    }

                }
            }

            if (!success) {
                // Fallback to window.open method
                console.log("No methods worked for saving the arraybuffer, using last resort window.open");
                window.open(httpPath, '_blank', '');
            }
            /******************/


        }).error(function (data, status) {

            console.log("Request failed with status: " + status);

            // Optionally write the error out to scope
            //$scope.errorDetails = "Request failed with status: " + status;
        });
}
1个回答

13

添加了arraybuffer作为GET请求的响应类型,现在浏览器可以正确解释文件。

    /******** FILE DOWNLOAD  **********/
$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'。但我没有想到这可能是一个重大问题。 - Aamol

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