简体   繁体   English

如何设置HTTP GET请求的标头,并触发文件下载?

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

Update 20140702: 更新 20140702:

(but I'm marking one of the other answers as accepted instead of my own, as it got me halfway there, and to reward the effort) (但我将其他答案标记为接受而不是我自己的答案,因为它让我在那里一半,并奖励努力)


It appears that setting a HTTP request header is not possible through links with <a href="..."> , and can only be done using XMLHttpRequest . 似乎无法通过与<a href="...">链接设置HTTP请求标头,并且只能使用XMLHttpRequest完成。

However, the URL linked to is a file that should be downloaded (browser should not navigate to its URL), and I am not sure is this can be done using AJAX. 但是,链接到的URL是应该下载的文件(浏览器不应该导航到它的URL),我不确定这是否可以使用AJAX完成。

Additionally, the file being returned is a binary file, and AJAX is not intended for that. 此外,返回的文件是二进制文件,而AJAX不适用于此。

How would one go about triggering a file download with a HTTP request that has a custom header added to it? 如何使用添加了自定义标头的HTTP请求触发文件下载?

edit: fix broken link 编辑:修复损坏的链接

There are two ways to download a file where the HTTP request requires that a header be set. 两种方法可以下载 HTTP请求要求设置标头的文件

The credit for the first goes to @guest271314, and credit for the second goes to @dandavis. 第一个的功劳归于@ guest271314,第二个功能归功于@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. 第一种方法是使用HTML5 File API创建临时本地文件,第二种方法是将base64编码与数据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. 我在项目中使用的解决方案对小文件使用base64编码方法,或者在File API不可用时使用,否则使用File API方法。

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. 请注意,我没有使用原始XMLHttpRequest ,而是使用ic-ajax ,并且应该与jQuery.ajax解决方案非常相似。

Note also that you should substitute text/bin and .bin with whatever corresponds to the file type being downloaded. 另请注意,您应该将text/bin.bin替换为与下载的文件类型相对应的内容。

The implementation of FormatUtils.utf8toBase64 can be found here 可以在此处找到 FormatUtils.utf8toBase64的实现

Try 尝试

html HTML

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

js 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/ jsfiddle http://jsfiddle.net/guest271314/SJYy3/

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). 上面的答案对我来说非常有用,但我想使用jQuery而不是ic-ajax(当我尝试通过bower安装时,它似乎与Ember有依赖关系)。 Keep in mind that this solution only works on modern browsers. 请记住,此解决方案仅适用于现代浏览器。

In order to implement this on jQuery I used jQuery BinaryTransport . 为了在jQuery上实现这一点,我使用了jQuery BinaryTransport This is a nice plugin to read AJAX responses in binary format. 这是一个很好的插件来读取二进制格式的AJAX响应。

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 url:文件的URL
  • headers: a Javascript object with the headers to send headers:包含要发送的标头的Javascript对象
  • fileName: the filename the user will see when downloading the file fileName:用户下载文件时将看到的文件名
  • anchor: it is a DOM element that is needed to simulate the download that must be wrapped with jQuery in this case. anchor:在这种情况下,它是模拟必须用jQuery包装的下载所需的DOM元素。 For example $('a.download-link') . 例如$('a.download-link')

i want to post my solution here which was done AngularJS, ASP.NET MVC. 我想在这里发布我的解决方案,这是完成AngularJS,ASP.NET MVC。 The code illustrates how to download file with authentication. 该代码说明了如何使用身份验证下载文件。

WebApi method along with helper class: WebApi方法和辅助类:

[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. Web.config文件更改为允许在自定义标头中发送文件名。

<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: Angular JS服务部分:

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). 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.

Pure jQuery. 纯粹的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);
  }
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM