Update 20140702:
更新20140702:
- The solution
- 解决方案
- Detailed answer as a blog post
- 详细答案作为一篇博客文章
(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();
}