How to set a header for a HTTP GET request, and trigger file download?

前端 未结 5 1241
不思量自难忘°
不思量自难忘° 2020-11-27 03:02

Update 20140702:

  • The solution
  • Detailed answer as a blog post

(but I\'m marking one of the other answers as accepted in

相关标签:
5条回答
  • 2020-11-27 03:23

    Pure jQuery.

    $.ajax({
      type: "GET",
      url: "https://example.com/file",
      headers: {
        'Authorization': 'Bearer eyJraWQiFUDA.......TZxX1MGDGyg'
      },
      xhrFields: {
        responseType: 'blob'
      },
      success: function (blob) {
        var windowUrl = window.URL || window.webkitURL;
        var url = windowUrl.createObjectURL(blob);
        var anchor = document.createElement('a');
        anchor.href = url;
        anchor.download = 'filename.zip';
        anchor.click();
        anchor.parentNode.removeChild(anchor);
        windowUrl.revokeObjectURL(url);
      },
      error: function (error) {
        console.log(error);
      }
    });
    
    0 讨论(0)
  • 2020-11-27 03:25

    I'm adding another option. The answers above were very useful for me, but I wanted to use jQuery instead of ic-ajax (it seems to have a dependency with Ember when I tried to install through bower). Keep in mind that this solution only works on modern browsers.

    In order to implement this on jQuery I used jQuery BinaryTransport. This is a nice plugin to read AJAX responses in binary format.

    Then you can do this to download the file and send the headers:

    $.ajax({
        url: url,
        type: 'GET',
        dataType: 'binary',
        headers: headers,
        processData: false,
        success: function(blob) {
            var windowUrl = window.URL || window.webkitURL;
            var url = windowUrl.createObjectURL(blob);
            anchor.prop('href', url);
            anchor.prop('download', fileName);
            anchor.get(0).click();
            windowUrl.revokeObjectURL(url);
        }
    });
    

    The vars in the above script mean:

    • url: the URL of the file
    • headers: a Javascript object with the headers to send
    • fileName: the filename the user will see when downloading the file
    • anchor: it is a DOM element that is needed to simulate the download that must be wrapped with jQuery in this case. For example $('a.download-link').
    0 讨论(0)
  • 2020-11-27 03:26

    Try

    html

    <!-- placeholder , 
        `click` download , `.remove()` options ,
         at js callback , following js 
    -->
    <a>download</a>
    

    js

            $(document).ready(function () {
                $.ajax({
                    // `url` 
                    url: '/echo/json/',
                    type: "POST",
                    dataType: 'json',
                    // `file`, data-uri, base64
                    data: {
                        json: JSON.stringify({
                            "file": "data:text/plain;base64,YWJj"
                        })
                    },
                    // `custom header`
                    headers: {
                        "x-custom-header": 123
                    },
                    beforeSend: function (jqxhr) {
                        console.log(this.headers);
                        alert("custom headers" + JSON.stringify(this.headers));
                    },
                    success: function (data) {
                        // `file download`
                        $("a")
                            .attr({
                            "href": data.file,
                                "download": "file.txt"
                        })
                            .html($("a").attr("download"))
                            .get(0).click();
                        console.log(JSON.parse(JSON.stringify(data)));
                    },
                    error: function (jqxhr, textStatus, errorThrown) {
                      console.log(textStatus, errorThrown)
                    }
                });
            });
    

    jsfiddle http://jsfiddle.net/guest271314/SJYy3/

    0 讨论(0)
  • 2020-11-27 03:27

    i want to post my solution here which was done AngularJS, ASP.NET MVC. The code illustrates how to download file with authentication.

    WebApi method along with helper class:

    [RoutePrefix("filess")]
    class FileController: ApiController
    {
        [HttpGet]
        [Route("download-file")]
        [Authorize(Roles = "admin")]
        public HttpResponseMessage DownloadDocument([FromUri] int fileId)
        {
            var file = "someFile.docx"// asking storage service to get file path with id
            return Request.ReturnFile(file);
        }
    }
    
    static class DownloadFIleFromServerHelper
    {
        public static HttpResponseMessage ReturnFile(this HttpRequestMessage request, string file)
        {
            var result = request.CreateResponse(HttpStatusCode.OK);
    
            result.Content = new StreamContent(new FileStream(file, FileMode.Open, FileAccess.Read));
            result.Content.Headers.Add("x-filename", Path.GetFileName(file)); // letters of header names will be lowercased anyway in JS.
            result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = Path.GetFileName(file)
            };
    
            return result;
        }
    }
    

    Web.config file changes to allow sending file name in custom header.

    <configuration>
        <system.webServer>
            <httpProtocol>
                <customHeaders>
                    <add name="Access-Control-Allow-Methods" value="POST,GET,PUT,PATCH,DELETE,OPTIONS" />
                    <add name="Access-Control-Allow-Headers" value="Authorization,Content-Type,x-filename" />
                    <add name="Access-Control-Expose-Headers" value="Authorization,Content-Type,x-filename" />
                    <add name="Access-Control-Allow-Origin" value="*" />
    

    Angular JS Service Part:

    function proposalService($http, $cookies, config, FileSaver) {
            return {
                    downloadDocument: downloadDocument
            };
    
        function downloadFile(documentId, errorCallback) {
        $http({
            url: config.apiUrl + "files/download-file?documentId=" + documentId,
            method: "GET",
            headers: {
                "Content-type": "application/json; charset=utf-8",
                "Authorization": "Bearer " + $cookies.get("api_key")
            },
            responseType: "arraybuffer"  
            })
        .success( function(data, status, headers) {
            var filename = headers()['x-filename'];
    
            var blob = new Blob([data], { type: "application/octet-binary" });
            FileSaver.saveAs(blob, filename);
        })
        .error(function(data, status) {
            console.log("Request failed with status: " + status);
            errorCallback(data, status);
        });
    };
    };
    

    Module dependency for FileUpload: angular-file-download (gulp install angular-file-download --save). Registration looks like below.

    var app = angular.module('cool',
    [
        ...
        require('angular-file-saver'),
    ])
    . // other staff.
    
    0 讨论(0)
  • 2020-11-27 03:28

    There are two ways to download a file where the HTTP request requires that a header be set.

    The credit for the first goes to @guest271314, and credit for the second goes to @dandavis.

    The first method is to use the HTML5 File API to create a temporary local file, and the second is to use base64 encoding in conjunction with a data URI.

    The solution I used in my project uses the base64 encoding approach for small files, or when the File API is not available, otherwise using the the File API approach.

    Solution:

            var id = 123;
    
            var req = ic.ajax.raw({
                type: 'GET',
                url: '/api/dowloads/'+id,
                beforeSend: function (request) {
                    request.setRequestHeader('token', 'token for '+id);
                },
                processData: false
            });
    
            var maxSizeForBase64 = 1048576; //1024 * 1024
    
            req.then(
                function resolve(result) {
                    var str = result.response;
    
                    var anchor = $('.vcard-hyperlink');
                    var windowUrl = window.URL || window.webkitURL;
                    if (str.length > maxSizeForBase64 && typeof windowUrl.createObjectURL === 'function') {
                        var blob = new Blob([result.response], { type: 'text/bin' });
                        var url = windowUrl.createObjectURL(blob);
                        anchor.prop('href', url);
                        anchor.prop('download', id+'.bin');
                        anchor.get(0).click();
                        windowUrl.revokeObjectURL(url);
                    }
                    else {
                        //use base64 encoding when less than set limit or file API is not available
                        anchor.attr({
                            href: 'data:text/plain;base64,'+FormatUtils.utf8toBase64(result.response),
                            download: id+'.bin',
                        });
                        anchor.get(0).click();
                    }
    
                }.bind(this),
                function reject(err) {
                    console.log(err);
                }
            );
    

    Note that I'm not using a raw XMLHttpRequest, and instead using ic-ajax, and should be quite similar to a jQuery.ajax solution.

    Note also that you should substitute text/bin and .bin with whatever corresponds to the file type being downloaded.

    The implementation of FormatUtils.utf8toBase64 can be found here

    0 讨论(0)
提交回复
热议问题