Mise à jour 20140702:
(Mais je marque l'une des autres réponses acceptées au lieu de la mienne, car elle m'a fait à mi-chemin, et pour récompenser l'effort)
Il semble que définir un en-tête de requête HTTP n'est pas possible grâce à des liens avec <a href="...">
, et ne peut être effectué qu'avec XMLHttpRequest
.
Cependant, l'URL liée est un fichier qui doit être téléchargé (le navigateur ne doit pas naviguer vers son URL), et je ne suis pas sûr que cela puisse être fait en utilisant AJAX.
En outre, le fichier renvoyé est un fichier binaire, et AJAX n'est pas destiné à cela.
Comment pourrait-on envisager de déclencher un téléchargement de fichier avec une requête HTTP qui comporte un en-tête personnalisé?
Modifier: corriger le lien brisé
essayer
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) } }); });
Il existe deux façons de télécharger un fichier dans lequel la requête HTTP requiert la définition d' un en-tête .
Le crédit pour le premier va à @ guest271314, et le crédit pour le second passe à @dandavis.
La première méthode consiste à utiliser l'API de fichiers HTML5 pour créer un fichier local temporaire et la seconde à utiliser l'encodage base64 en conjonction avec un URI de données.
La solution que j'ai utilisée dans mon projet utilise l'approche de codage base64 pour les petits fichiers, ou lorsque l'API du fichier n'est pas disponible, sinon l'approche API du fichier.
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); } );
Notez que je n'utilise pas un XMLHttpRequest
en cours et utilise plutôt ic-ajax , et devrait être assez similaire à une solution jQuery.ajax
.
Notez également que vous devez remplacer text/bin
et .bin
par tout ce qui correspond au type de fichier en cours de téléchargement.
La mise en œuvre de FormatUtils.utf8toBase64
se trouve ici
J'ajoute une autre option. Les réponses ci-dessus m'ont été très utiles, mais je voulais utiliser jQuery au lieu d'ic-ajax (il semble avoir une dépendance avec Ember lorsque j'ai essayé d'installer à travers bower). Gardez à l'esprit que cette solution ne fonctionne que sur les navigateurs modernes.
Pour l'implémenter sur jQuery, j'ai utilisé jQuery BinaryTransport . C'est un bon plugin pour lire les réponses AJAX au format binaire.
Ensuite, vous pouvez le faire pour télécharger le fichier et envoyer les en-têtes:
$.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); } });
Les vars dans le script ci-dessus signifient:
$('a.download-link')
. Je souhaite publier ici ma solution qui a été effectuée AngularJS, ASP.NET MVC. Le code illustre comment télécharger le fichier avec l'authentification.
Méthode WebApi avec classe auxiliaire:
[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; } }
Les modifications du fichier Web.config permettent d'envoyer le nom du fichier dans l'en-tête personnalisé.
<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="*" />
Pièce de service angulaire 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); }); }; };
Dépendance de module pour FileUpload: angular-file-download (gulp install angular-file-download –save). L'inscription se ressemble ci-dessous.
var app = angular.module('cool', [ ... require('angular-file-saver'), ]) . // other staff.
1) dans jQuery
$('a.some-random-link').click(function(e) { e.preventDefault(); //stop the browser from following window.location.href = 'uploads/crazy-fractals.jpg'; });
2) en html avec l'attribut de download
, mon préféré :
<a href="/path/to/file.extension" download>download</a>
VÉRIFIEZ CANIUSE.COM POUR LA COMPATIBILITÉ
3) js, j'ai aussi vu de temps en temps:
function downloadFileFromLocation(fileName, url) { var dl = document.createElement('a'); dl.download = fileName; dl.href = url; dl.click(); }