javascript download - Télécharger un fichier par jQuery.Ajax




file pdf (13)

Personne n'a posté cette solution @ Pekka ... alors je l'afficherai. Cela peut aider quelqu'un.

Vous ne pouvez pas et n'avez pas besoin de le faire via Ajax. Juste utiliser

window.location="download.action?para1=value1...."

J'ai une action Struts2 côté serveur pour le téléchargement de fichiers.

<action name="download" class="com.xxx.DownAction">
    <result name="success" type="stream">
        <param name="contentType">text/plain</param>
        <param name="inputName">imageStream</param>
        <param name="contentDisposition">attachment;filename={fileName}</param>
        <param name="bufferSize">1024</param>
    </result>
</action>

Cependant, quand j'appelle l'action en utilisant le jQuery:

$.post(
  "/download.action",{
    para1:value1,
    para2:value2
    ....
  },function(data){
      console.info(data);
   }
);

dans Firebug, je vois que les données sont récupérées avec le flux binaire . Je me demande comment ouvrir la fenêtre de téléchargement de fichiers avec laquelle l'utilisateur peut enregistrer le fichier localement?


Ok, basé sur le code de ndpu, voici une version améliorée (je pense) d'ajax_download;

function ajax_download(url, data) {
    var $iframe,
        iframe_doc,
        iframe_html;

    if (($iframe = $('#download_iframe')).length === 0) {
        $iframe = $("<iframe id='download_iframe'" +
                    " style='display: none' src='about:blank'></iframe>"
                   ).appendTo("body");
    }

    iframe_doc = $iframe[0].contentWindow || $iframe[0].contentDocument;
    if (iframe_doc.document) {
        iframe_doc = iframe_doc.document;
    }

    iframe_html = "<html><head></head><body><form method='POST' action='" +
                  url +"'>" 

    Object.keys(data).forEach(function(key){
        iframe_html += "<input type='hidden' name='"+key+"' value='"+data[key]+"'>";

    });

        iframe_html +="</form></body></html>";

    iframe_doc.open();
    iframe_doc.write(iframe_html);
    $(iframe_doc).find('form').submit();
}

Utilisez ceci comme ceci:

$('#someid').on('click', function() {
    ajax_download('/download.action', {'para1': 1, 'para2': 2});
});

Les paramètres sont envoyés en tant que paramètres de post appropriés comme s'ils provenaient d'une entrée plutôt que d'une chaîne codée en json comme dans l'exemple précédent.

CAVEAT: Méfiez-vous du potentiel d'injection variable sur ces formes. Il pourrait y avoir un moyen plus sûr d'encoder ces variables. Alternativement envisager de leur échapper.


Dans Rails, je le fais de cette façon:

function download_file(file_id) {
  let url       = '/files/' + file_id + '/download_file';
    $.ajax({
    type: 'GET',
    url: url,
    processData: false,
    success: function (data) {
       window.location = url;
    },
    error: function (xhr) {
     console.log(' Error:  >>>> ' + JSON.stringify(xhr));
    }
   });
 }

L'astuce est la partie window.location . La méthode du contrôleur ressemble à:

# GET /files/{:id}/download_file/
def download_file
    send_file(@file.file,
          :disposition => 'attachment',
          :url_based_filename => false)
end

J'ai créé peu de fonction en tant que solution de contournement (inspirée du plugin @JohnCulviner):

// creates iframe and form in it with hidden field,
// then submit form with provided data
// url - form url
// data - data to form field
// input_name - form hidden input name

function ajax_download(url, data, input_name) {
    var $iframe,
        iframe_doc,
        iframe_html;

    if (($iframe = $('#download_iframe')).length === 0) {
        $iframe = $("<iframe id='download_iframe'" +
                    " style='display: none' src='about:blank'></iframe>"
                   ).appendTo("body");
    }

    iframe_doc = $iframe[0].contentWindow || $iframe[0].contentDocument;
    if (iframe_doc.document) {
        iframe_doc = iframe_doc.document;
    }

    iframe_html = "<html><head></head><body><form method='POST' action='" +
                  url +"'>" +
                  "<input type=hidden name='" + input_name + "' value='" +
                  JSON.stringify(data) +"'/></form>" +
                  "</body></html>";

    iframe_doc.open();
    iframe_doc.write(iframe_html);
    $(iframe_doc).find('form').submit();
}

Démo avec événement click:

$('#someid').on('click', function() {
    ajax_download('/download.action', {'para1': 1, 'para2': 2}, 'dataname');
});

Ok donc voici le code de travail lors de l'utilisation de MVC et vous obtenez votre fichier à partir d'un contrôleur

disons que vous avez votre tableau d'octets déclarent et peuplent, la seule chose que vous devez faire est d'utiliser la fonction Fichier (en utilisant System.Web.Mvc)

byte[] bytes = .... insert your bytes in the array
return File(bytes, System.Net.Mime.MediaTypeNames.Application.Octet, "nameoffile.exe");

puis, dans le même contrôleur, ajoutez ces deux fonctions

protected override void OnResultExecuting(ResultExecutingContext context)
    {
        CheckAndHandleFileResult(context);

        base.OnResultExecuting(context);
    }

    private const string FILE_DOWNLOAD_COOKIE_NAME = "fileDownload";

    /// <summary>
    /// If the current response is a FileResult (an MVC base class for files) then write a
    /// cookie to inform jquery.fileDownload that a successful file download has occured
    /// </summary>
    /// <param name="context"></param>
    private void CheckAndHandleFileResult(ResultExecutingContext context)
    {
        if (context.Result is FileResult)
            //jquery.fileDownload uses this cookie to determine that a file download has completed successfully
            Response.SetCookie(new HttpCookie(FILE_DOWNLOAD_COOKIE_NAME, "true") { Path = "/" });
        else
            //ensure that the cookie is removed in case someone did a file download without using jquery.fileDownload
            if (Request.Cookies[FILE_DOWNLOAD_COOKIE_NAME] != null)
                Response.Cookies[FILE_DOWNLOAD_COOKIE_NAME].Expires = DateTime.Now.AddYears(-1);
    }

et alors vous serez en mesure d'appeler votre contrôleur pour télécharger et obtenir le rappel "succès" ou "échec"

$.fileDownload(mvcUrl('name of the controller'), {
            httpMethod: 'POST',
            successCallback: function (url) {
            //insert success code

            },
            failCallback: function (html, url) {
            //insert fail code
            }
        });

J'ai trouvé un correctif qui, bien qu'il n'utilise pas réellement ajax, vous permet d'utiliser un appel javascript pour demander le téléchargement et obtenir un rappel lorsque le téléchargement commence réellement. J'ai trouvé cela utile si le lien exécute un script côté serveur qui prend un peu de temps pour composer le fichier avant de l'envoyer. donc vous pouvez les alerter que c'est le traitement, puis quand il envoie finalement le fichier supprimer cette notification de traitement. C'est pourquoi je voulais d'abord charger le fichier via ajax afin que je puisse avoir un événement quand le fichier est demandé et un autre lorsqu'il commence à télécharger.

le js sur la première page

function expdone()
{
    document.getElementById('exportdiv').style.display='none';
}
function expgo()
{
   document.getElementById('exportdiv').style.display='block';
   document.getElementById('exportif').src='test2.php?arguments=data';
}

l'iframe

<div id="exportdiv" style="display:none;">
<img src="loader.gif"><br><h1>Generating Report</h1>
<iframe id="exportif" src="" style="width: 1px;height: 1px; border:0px;"></iframe>
</div>

puis l'autre fichier:

<!DOCTYPE html>
<html>
<head>
<script>
function expdone()
{
    window.parent.expdone();
}
</script>
</head>
<body>
<iframe id="exportif" src="<?php echo "http://10.192.37.211/npdtracker/exportthismonth.php?arguments=".$_GET["arguments"]; ?>"></iframe>
<script>document.getElementById('exportif').onload= expdone;</script>
</body></html>

Je pense qu'il y a un moyen de lire obtenir des données en utilisant js alors aucun php ne serait nécessaire. mais je ne le connais pas de la main et le serveur que j'utilise supporte PHP donc cela fonctionne pour moi. J'ai pensé que je le partagerais au cas où ça aiderait quelqu'un.


Si vous voulez utiliser le téléchargement de fichiers jQuery, veuillez le noter pour IE. Vous devez réinitialiser la réponse ou celle-ci ne sera pas téléchargée

    //The IE will only work if you reset response
    getServletResponse().reset();
    //The jquery.fileDownload needs a cookie be set
    getServletResponse().setHeader("Set-Cookie", "fileDownload=true; path=/");
    //Do the reset of your action create InputStream and return

Votre action peut implémenter ServletResponseAware pour accéder à getServletResponse()


Ajouter plus de choses à ci-dessus répondre pour télécharger un fichier

Ci-dessous est un code java spring qui génère byte Array

@RequestMapping(value = "/downloadReport", method = { RequestMethod.POST })
    public ResponseEntity<byte[]> downloadReport(
            @RequestBody final SomeObejct obj, HttpServletResponse response) throws Exception {

        OutputStream out = new ByteArrayOutputStream();
        // write something to output stream
        HttpHeaders respHeaders = new HttpHeaders();
        respHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        respHeaders.add("X-File-Name", name);
        ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
        return new ResponseEntity<byte[]>(bos.toByteArray(), respHeaders, HttpStatus.CREATED);
    }

Maintenant, dans le code javascript en utilisant FileSaver.js, vous pouvez télécharger un fichier avec le code ci-dessous

var json=angular.toJson("somejsobject");
var url=apiEndPoint+'some url';
var xhr = new XMLHttpRequest();
//headers('X-File-Name')
xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 201) {
        var res = this.response;
        var fileName=this.getResponseHeader('X-File-Name');
        var data = new Blob([res]);
        saveAs(data, fileName); //this from FileSaver.js
    }
}    
xhr.open('POST', url);
xhr.setRequestHeader('Authorization','Bearer ' + token);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.responseType = 'arraybuffer';
xhr.send(json);

Le ci-dessus va télécharger le fichier


Bluish fait raison à ce sujet, vous ne pouvez pas le faire via Ajax car JavaScript ne peut pas enregistrer les fichiers directement sur l'ordinateur d'un utilisateur (pour des raisons de sécurité). Malheureusement, le fait de pointer l'URL de la fenêtre principale lors du téléchargement de votre fichier signifie que vous avez peu de contrôle sur l'expérience de l'utilisateur lors du téléchargement d'un fichier.

J'ai créé le téléchargement de fichiers jQuery qui permet une expérience "Ajax like" avec des téléchargements de fichiers complets avec des rappels OnSuccess et OnFailure pour fournir une meilleure expérience utilisateur. Jetez un oeil à mon blog sur le problème commun que le plugin résout et quelques façons de l'utiliser et aussi une démo de jQuery File Download en action . Voici la source

Voici une démo de cas d'utilisation simple utilisant la source plugin avec des promesses. La page de démonstration comprend également de nombreux autres exemples de «meilleurs UX».

$.fileDownload('some/file.pdf')
    .done(function () { alert('File download a success!'); })
    .fail(function () { alert('File download failed!'); });

En fonction des navigateurs que vous devez prendre en charge, vous pouvez utiliser https://github.com/eligrey/FileSaver.js/ qui permet un contrôle plus explicite que la méthode IFRAME que jQuery File Download utilise.


La façon simple de faire télécharger un fichier par le navigateur est de faire la requête comme ça:

 function downloadFile(urlToSend) {
     var req = new XMLHttpRequest();
     req.open("GET", urlToSend, true);
     req.responseType = "blob";
     req.onload = function (event) {
         var blob = req.response;
         var fileName = req.getResponseHeader("fileName") //if you have the fileName header available
         var link=document.createElement('a');
         link.href=window.URL.createObjectURL(blob);
         link.download=fileName;
         link.click();
     };

     req.send();
 }

Cela ouvre le téléchargement du navigateur.


Voici ce que j'ai fait, javascript pur et html. N'a pas testé, mais cela devrait fonctionner dans tous les navigateurs.

Fonction Javascript

var iframe = document.createElement('iframe');
iframe.id = "IFRAMEID";
iframe.style.display = 'none';
document.body.appendChild(iframe);
iframe.src = 'SERVERURL'+'?' + $.param($scope.filtro);
iframe.addEventListener("load", function () {
     console.log("FILE LOAD DONE.. Download should start now");
});

En utilisant uniquement des composants pris en charge dans tous les navigateurs, aucune bibliothèque supplémentaire.

Voici mon code de contrôleur JAVA Spring côté serveur.

@RequestMapping(value = "/rootto/my/xlsx", method = RequestMethod.GET)
public void downloadExcelFile(@RequestParam(value = "param1", required = false) String param1,
    HttpServletRequest request, HttpServletResponse response)
            throws ParseException {

    Workbook wb = service.getWorkbook(param1);
    if (wb != null) {
        try {
            String fileName = "myfile_" + sdf.format(new Date());
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-disposition", "attachment; filename=\"" + fileName + ".xlsx\"");
            wb.write(response.getOutputStream());
            response.getOutputStream().close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    }

function downloadURI(uri, name) 
{
    var link = document.createElement("a");
    link.download = name;
    link.href = uri;
    link.click();
}

Je viens de construire cette fonction en fonction de certaines informations que j'ai lues.

Utilisez-le comme en utilisant .serialize() , placez .serializefiles(); .
Travailler ici dans mes tests.

//USAGE: $("#form").serializefiles();
(function($) {
$.fn.serializefiles = function() {
    var obj = $(this);
    /* ADD FILE TO PARAM AJAX */
    var formData = new FormData();
    $.each($(obj).find("input[type='file']"), function(i, tag) {
        $.each($(tag)[0].files, function(i, file) {
            formData.append(tag.name, file);
        });
    });
    var params = $(obj).serializeArray();
    $.each(params, function (i, val) {
        formData.append(val.name, val.value);
    });
    return formData;
};
})(jQuery);






javascript jquery ajax jsp download