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

时间:2022-08-22 19:39:10

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.

看起来,通过与

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

编辑:修复破碎的链接

5 个解决方案

#1


7  

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/

#2


34  

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文件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编码方法来处理小文件,或者当文件API不可用时,使用文件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.

还请注意,您应该将文本/bin和.bin替换为与正在下载的文件类型相对应的任何内容。

The implementation of FormatUtils.utf8toBase64 can be found here

FormatUtils的实现。在这里可以找到utf8toBase64。

#3


10  

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.

我添加另一个选择。上面的答案对我非常有用,但我想使用jQuery而不是ic-ajax(当我尝试通过bower安装时,它似乎与Ember有依赖关系)。请记住,此解决方案仅适用于现代浏览器。

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

为了在jQuery上实现这一点,我使用了jQuery BinaryTransport。这是一个很好的插件来读取二进制格式的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:

上图中的vars表示:

  • url: the URL of the file
  • url:文件的url
  • headers: a Javascript object with the headers to send
  • header:带有要发送的header的Javascript对象
  • 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').
  • 锚:它是一个DOM元素,需要用jQuery来模拟下载。例如美元(“a.download-link”)。

#4


4  

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

我想在这里发布我的解决方案,它是用AngularJS, ASP完成的。净MVC。该代码演示了如何使用身份验证下载文件。

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.

网络。配置文件更改以允许在自定义头中发送文件名。

<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:

角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). Registration looks like below.

文件上传的模块依赖项:angular-file下载(gulp安装angular-file下载——save)。下面的注册的样子。

var app = angular.module('cool',
[
    ...
    require('angular-file-saver'),
])
. // other staff.

#5


-5  

Note: This answer does not address the setting of a custom header, due to misread; however, here are several methods for triggering file download. Thanks to @bguiz and @Vivek for feedback.

1) in jQuery

1)在jQuery

$('a.some-random-link').click(function(e) {
    e.preventDefault();  //stop the browser from following
    window.location.href = 'uploads/crazy-fractals.jpg';
});

2) in html with download attribute, my favorite:

2)在带有下载属性的html中,我最喜欢:

<a href="/path/to/file.extension" download>download</a>

CHECK CANIUSE.COM FOR COMPATIBILITY

检查CANIUSE。COM的兼容性

3) js, i've also seen occasionally:

3)js,我也偶尔看到:

function downloadFileFromLocation(fileName, url) {
  var dl = document.createElement('a');
  dl.download = fileName;
  dl.href = url;
  dl.click();
}

#1


7  

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/

#2


34  

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文件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编码方法来处理小文件,或者当文件API不可用时,使用文件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.

还请注意,您应该将文本/bin和.bin替换为与正在下载的文件类型相对应的任何内容。

The implementation of FormatUtils.utf8toBase64 can be found here

FormatUtils的实现。在这里可以找到utf8toBase64。

#3


10  

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.

我添加另一个选择。上面的答案对我非常有用,但我想使用jQuery而不是ic-ajax(当我尝试通过bower安装时,它似乎与Ember有依赖关系)。请记住,此解决方案仅适用于现代浏览器。

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

为了在jQuery上实现这一点,我使用了jQuery BinaryTransport。这是一个很好的插件来读取二进制格式的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:

上图中的vars表示:

  • url: the URL of the file
  • url:文件的url
  • headers: a Javascript object with the headers to send
  • header:带有要发送的header的Javascript对象
  • 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').
  • 锚:它是一个DOM元素,需要用jQuery来模拟下载。例如美元(“a.download-link”)。

#4


4  

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

我想在这里发布我的解决方案,它是用AngularJS, ASP完成的。净MVC。该代码演示了如何使用身份验证下载文件。

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.

网络。配置文件更改以允许在自定义头中发送文件名。

<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:

角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). Registration looks like below.

文件上传的模块依赖项:angular-file下载(gulp安装angular-file下载——save)。下面的注册的样子。

var app = angular.module('cool',
[
    ...
    require('angular-file-saver'),
])
. // other staff.

#5


-5  

Note: This answer does not address the setting of a custom header, due to misread; however, here are several methods for triggering file download. Thanks to @bguiz and @Vivek for feedback.

1) in jQuery

1)在jQuery

$('a.some-random-link').click(function(e) {
    e.preventDefault();  //stop the browser from following
    window.location.href = 'uploads/crazy-fractals.jpg';
});

2) in html with download attribute, my favorite:

2)在带有下载属性的html中,我最喜欢:

<a href="/path/to/file.extension" download>download</a>

CHECK CANIUSE.COM FOR COMPATIBILITY

检查CANIUSE。COM的兼容性

3) js, i've also seen occasionally:

3)js,我也偶尔看到:

function downloadFileFromLocation(fileName, url) {
  var dl = document.createElement('a');
  dl.download = fileName;
  dl.href = url;
  dl.click();
}