使用 AngularJS 从 ASP.NET Web API 方法下载文件 [英] Download file from an ASP.NET Web API method using AngularJS

查看:29
本文介绍了使用 AngularJS 从 ASP.NET Web API 方法下载文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的 Angular JS 项目中,我有一个 <a> 锚标记,单击该标记时会向返回文件的 WebAPI 方法发出 HTTP GET 请求.

In my Angular JS project, I've an <a> anchor tag, which when clicked makes an HTTP GET request to a WebAPI method that returns a file.

现在,我希望在请求成功后将文件下载给用户.我该怎么做?

Now, I want the file to be downloaded to the user once the request is successful. How do I do that?

锚标签:

<a href="#" ng-click="getthefile()">Download img</a>

AngularJS:

$scope.getthefile = function () {        
    $http({
        method: 'GET',
        cache: false,
        url: $scope.appPath + 'CourseRegConfirm/getfile',            
        headers: {
            'Content-Type': 'application/json; charset=utf-8'
        }
    }).success(function (data, status) {
        console.log(data); // Displays text data if the file is a text file, binary if it's an image            
        // What should I write here to download the file I receive from the WebAPI method?
    }).error(function (data, status) {
        // ...
    });
}

我的 WebAPI 方法:

My WebAPI method:

[Authorize]
[Route("getfile")]
public HttpResponseMessage GetTestFile()
{
    HttpResponseMessage result = null;
    var localFilePath = HttpContext.Current.Server.MapPath("~/timetable.jpg");

    if (!File.Exists(localFilePath))
    {
        result = Request.CreateResponse(HttpStatusCode.Gone);
    }
    else
    {
        // Serve the file to the client
        result = Request.CreateResponse(HttpStatusCode.OK);
        result.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
        result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
        result.Content.Headers.ContentDisposition.FileName = "SampleImg";                
    }

    return result;
}

推荐答案

使用ajax下载二进制文件的支持不是很好,还是很正在作为工作草案开发.

Support for downloading binary files in using ajax is not great, it is very much still under development as working drafts.

您只需使用下面的代码即可让浏览器下载请求的文件,并且所有浏览器都支持这种方式,并且显然会同样触发 WebApi 请求.

You can have the browser download the requested file simply by using the code below, and this is supported in all browsers, and will obviously trigger the WebApi request just the same.

$scope.downloadFile = function(downloadPath) { 
    window.open(downloadPath, '_blank', '');  
}

Ajax二进制下载方法:

可以在某些浏览器中使用 ajax 下载二进制文件,以下是适用于最新版本的 Chrome、Internet Explorer、FireFox 和 Safari 的实现.

Ajax binary download method:

Using ajax to download the binary file can be done in some browsers and below is an implementation that will work in the latest flavours of Chrome, Internet Explorer, FireFox and Safari.

它使用 arraybuffer 响应类型,然后将其转换为 JavaScript blob,然后使用 saveBlob 呈现以保存方法 - 尽管目前仅在 Internet Explorer 中存在 - 或者转换为由浏览器打开的 blob 数据 URL,如果浏览器支持查看 mime 类型,则会触发下载对话框.

It uses an arraybuffer response type, which is then converted into a JavaScript blob, which is then either presented to save using the saveBlob method - though this is only currently present in Internet Explorer - or turned into a blob data URL which is opened by the browser, triggering the download dialog if the mime type is supported for viewing in the browser.

注意:Internet Explorer 11 不喜欢使用具有别名的 msSaveBlob 函数 - 可能是安全功能,但更可能是一个缺陷,因此使用 var saveBlob =navigator.msSaveBlob ||navigator.webkitSaveBlob ... etc. 确定可用的 saveBlob 支持导致异常;因此,为什么下面的代码现在单独测试 navigator.msSaveBlob.谢谢?微软

Note: Internet Explorer 11 did not like using the msSaveBlob function if it had been aliased - perhaps a security feature, but more likely a flaw, So using var saveBlob = navigator.msSaveBlob || navigator.webkitSaveBlob ... etc. to determine the available saveBlob support caused an exception; hence why the code below now tests for navigator.msSaveBlob separately. Thanks? Microsoft

// Based on an implementation here: web.student.tuwien.ac.at/~e0427417/jsdownload.html
$scope.downloadFile = function(httpPath) {
    // Use an arraybuffer
    $http.get(httpPath, { responseType: 'arraybuffer' })
    .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
        {
            // 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;
    });
};

用法:

var downloadPath = "/files/instructions.pdf";
$scope.downloadFile(downloadPath);

注意事项:

您应该修改您的 WebApi 方法以返回以下标头:

Notes:

You should modify your WebApi method to return the following headers:

  • 我使用了 x-filename 标头来发送文件名.为方便起见,这是一个自定义标头,但是您可以使用正则表达式从 content-disposition 标头中提取文件名.

  • I have used the x-filename header to send the filename. This is a custom header for convenience, you could however extract the filename from the content-disposition header using regular expressions.

您也应该为您的响应设置 content-type mime 标头,以便浏览器知道数据格式.

You should set the content-type mime header for your response too, so the browser knows the data format.

我希望这会有所帮助.

这篇关于使用 AngularJS 从 ASP.NET Web API 方法下载文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆