Download een bestand van jQuery.Ajax

Ik heb een Struts2-actie aan de serverzijde voor het downloaden van bestanden.

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

Maar als ik de actie aanroep met de jQuery:

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

in Firebug zie ik dat de gegevens worden opgehaald met de Binaire stream. Ik vraag me af hoe ik het venster voor het downloaden van bestandenkan openen waarmee de gebruiker het bestand lokaal kan opslaan?


Antwoord 1, autoriteit 100%

Update moderne browsers 2019

Dit is de aanpak die ik nu zou aanraden, met een paar kanttekeningen:

  • Een relatief moderne browser is vereist
  • Als het bestand naar verwachting zeer grootzal zijn, moet u waarschijnlijk iets doen dat lijkt op de oorspronkelijke aanpak (iframe en cookie), omdat sommige van de onderstaande bewerkingen waarschijnlijk systeemgeheugen in beslag nemen dat minstens zo groot is als het bestand dat wordt gedownload en/of andere interessante bijwerkingen van de CPU.
fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(resp => resp.blob())
  .then(blob => {
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    // the filename you want
    a.download = 'todo-1.json';
    document.body.appendChild(a);
    a.click();
    window.URL.revokeObjectURL(url);
    alert('your file has downloaded!'); // or you know, something with better UX...
  })
  .catch(() => alert('oh no!'));

Antwoord 2, autoriteit 33%

Niemand heeft deze @Pekka’s oplossinggepost.. dus ik zal het posten. Het kan iemand helpen.

U hoeft dit niet via Ajax te doen. Gebruik gewoon

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

Antwoord 3, autoriteit 6%

Dat kan met HTML5

NB: De geretourneerde bestandsgegevens MOETEN base64-gecodeerd zijn omdat u binaire gegevens niet kunt JSON-coderen

In mijn AJAX-antwoord heb ik een gegevensstructuur die er als volgt uitziet:

{
    result: 'OK',
    download: {
        mimetype: string(mimetype in the form 'major/minor'),
        filename: string(the name of the file to download),
        data: base64(the binary data as base64 to download)
    }
}

Dat betekent dat ik het volgende kan doen om een bestand op te slaan via AJAX

var a = document.createElement('a');
if (window.URL && window.Blob && ('download' in a) && window.atob) {
    // Do it the HTML5 compliant way
    var blob = base64ToBlob(result.download.data, result.download.mimetype);
    var url = window.URL.createObjectURL(blob);
    a.href = url;
    a.download = result.download.filename;
    a.click();
    window.URL.revokeObjectURL(url);
}

De functie base64ToBlob is hierovergenomen en moet worden gebruikt in overeenstemming met deze functie

function base64ToBlob(base64, mimetype, slicesize) {
    if (!window.atob || !window.Uint8Array) {
        // The current browser doesn't have the atob function. Cannot continue
        return null;
    }
    mimetype = mimetype || '';
    slicesize = slicesize || 512;
    var bytechars = atob(base64);
    var bytearrays = [];
    for (var offset = 0; offset < bytechars.length; offset += slicesize) {
        var slice = bytechars.slice(offset, offset + slicesize);
        var bytenums = new Array(slice.length);
        for (var i = 0; i < slice.length; i++) {
            bytenums[i] = slice.charCodeAt(i);
        }
        var bytearray = new Uint8Array(bytenums);
        bytearrays[bytearrays.length] = bytearray;
    }
    return new Blob(bytearrays, {type: mimetype});
};

Dit is goed als uw server bestandsgegevens dumpt die moeten worden opgeslagen. Ik ben er echter nog niet helemaal uit hoe je een HTML4 fallback zou implementeren


Antwoord 4, autoriteit 4%

De eenvoudige manier om de browser een bestand te laten downloaden, is door het verzoek als volgt te doen:

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();
 }

Hiermee wordt de pop-up voor het downloaden van de browser geopend.


Antwoord 5, autoriteit 4%

1. Framework-agnostisch: Servlet downloadt bestand als bijlage

<!-- with JS -->
<a href="javascript:window.location='downloadServlet?param1=value1'">
    download
</a>
<!-- without JS -->
<a href="downloadServlet?param1=value1" >download</a>

2. Struts2 Framework: Actie downloaden bestand als bijlage

<!-- with JS -->
<a href="javascript:window.location='downloadAction.action?param1=value1'">
    download
</a>
<!-- without JS -->
<a href="downloadAction.action?param1=value1" >download</a>

Het zou beter zijn om de <s:a>-tag te gebruiken die met OGNLverwijst naar een URLgemaakt met <s:url>-tag:

<!-- without JS, with Struts tags: THE RIGHT WAY -->    
<s:url action="downloadAction.action" var="url">
    <s:param name="param1">value1</s:param>
</s:ulr>
<s:a href="%{url}" >download</s:a>

In de bovenstaande gevallen moet u nodigde kop Content-Dispositionnaar de responseschrijven, waarbij u aangeeft dat het bestand moet worden gedownload (attachment) en niet geopend door de browser (inline). Je moetook het Inhoudstypespecificeren, en misschien wil je de bestandsnaam en lengte toevoegen (om de browser te helpen een realistische voortgangsbalk te tekenen).

Bijvoorbeeld bij het downloaden van een ZIP:

response.setContentType("application/zip");
response.addHeader("Content-Disposition", 
                   "attachment; filename=\"name of my file.zip\"");
response.setHeader("Content-Length", myFile.length()); // or myByte[].length...

Met Struts2 (tenzij je de Action gebruikt als een Servlet, bijvoorbeeld een hack voor directe streaming), u hoeft niet direct iets naar het antwoord te schrijven; gewoon met behulp van het Streamresultaat typen het configureren in struts.xml werkt: VOORBEELD

<result name="success" type="stream">
   <param name="contentType">application/zip</param>
   <param name="contentDisposition">attachment;filename="${fileName}"</param>
   <param name="contentLength">${fileLength}</param>
</result>

3. Framework-agnostisch (/ Struts2-framework): Servlet (/Action) openingsbestand in de browser

Als u het bestand in de browser wilt openen, in plaats van het te downloaden, moet de Content-dispositionzijn ingesteld op inline, maar het doel kan niet worden de huidige vensterlocatie; u moet zich richten op een nieuw venster gemaakt door javascript, een <iframe>in de pagina, of een nieuw venster dat on-the-fly is gemaakt met de “besproken” target=”_blank”:

<!-- From a parent page into an IFrame without javascript -->   
<a href="downloadServlet?param1=value1" target="iFrameName">
    download
</a>
<!-- In a new window without javascript --> 
<a href="downloadServlet?param1=value1" target="_blank">
    download
</a>
<!-- In a new window with javascript -->    
<a href="javascript:window.open('downloadServlet?param1=value1');" >
    download
</a>

Antwoord 6, autoriteit 3%

Ik heb een kleine functie gemaakt als tijdelijke oplossing (geïnspireerd door de @JohnCulviner-plug-in):

// 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();
}

Demo met klikgebeurtenis:

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

Antwoord 7, autoriteit 2%

Ik had hetzelfde probleem en heb het met succes opgelost. Mijn use-case is dit.

Plaats JSON-gegevens op de server en ontvang een Excel-bestand.
Dat Excel-bestand wordt door de server gemaakt en als reactie aan de client geretourneerd. Download dat antwoord als een bestand met aangepaste naam in browser

$("#my-button").on("click", function(){
// Data to post
data = {
    ids: [1, 2, 3, 4, 5]
};
// Use XMLHttpRequest instead of Jquery $ajax
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    var a;
    if (xhttp.readyState === 4 && xhttp.status === 200) {
        // Trick for making downloadable link
        a = document.createElement('a');
        a.href = window.URL.createObjectURL(xhttp.response);
        // Give filename you wish to download
        a.download = "test-file.xls";
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
    }
};
// Post data to URL which handles post request
xhttp.open("POST", excelDownloadUrl);
xhttp.setRequestHeader("Content-Type", "application/json");
// You should set responseType as blob for binary responses
xhttp.responseType = 'blob';
xhttp.send(JSON.stringify(data));
});

Het bovenstaande fragment is gewoon aan het volgen

  • Een array als JSON op de server plaatsen met XMLHttpRequest.
  • Na het ophalen van inhoud als een blob (binair), maken we een downloadbare URL en koppelen deze aan een onzichtbare “a”-link en klikken erop. Ik heb hier een POST-verzoek gedaan. In plaats daarvan kun je ook voor een eenvoudige GET gaan. We kunnen het bestand niet downloaden via Ajax, we moeten XMLHttpRequest gebruiken.

Hier moeten we een paar dingen zorgvuldig instellen aan de serverkant. Ik heb een paar headers ingesteld in Python Django HttpResponse. Je moet ze dienovereenkomstig instellen als je andere programmeertalen gebruikt.

# In python django code
response = HttpResponse(file_content, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")

Sinds ik xls(excel) hier download, heb ik contentType aangepast naar boven één. U moet het instellen volgens uw bestandstype. Je kunt deze techniek gebruiken om alle soorten bestanden te downloaden.


Antwoord 8, autoriteit 2%

Ok, op basis van de code van ndpu is hier een verbeterde (denk ik) versie van 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();
}

Gebruik dit als volgt;-

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

De params worden verzonden als correcte post-params alsof ze afkomstig zijn van een invoer in plaats van als een json-gecodeerde string zoals in het vorige voorbeeld.

WAARSCHUWING: wees op uw hoede voor de mogelijkheid van variabele injectie op die vormen. Er is misschien een veiligere manier om die variabelen te coderen. U kunt ook overwegen om eraan te ontsnappen.


Antwoord 9

Dit is wat ik deed, pure javascript en html. Ik heb het niet getest, maar dit zou in alle browsers moeten werken.

Javascript-functie

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");
});

Alleen componenten gebruiken die in alle browsers worden ondersteund, geen extra
bibliotheken.


Hier is mijn Server Side Java Spring Controller Code.

@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();
        }
    }
    }

10

Hoe een bestand downloaden na ontvangst door Ajax

Het is handig als het bestand voor een lange tijd is gemaakt en u moet PRELOader

tonen

Voorbeeld bij het indienen van een webformulier:

<script>
$(function () {
    $('form').submit(function () {
        $('#loader').show();
        $.ajax({
            url: $(this).attr('action'),
            data: $(this).serialize(),
            dataType: 'binary',
            xhrFields: {
                'responseType': 'blob'
            },
            success: function(data, status, xhr) {
                $('#loader').hide();
                // if(data.type.indexOf('text/html') != -1){//If instead of a file you get an error page
                //     var reader = new FileReader();
                //     reader.readAsText(data);
                //     reader.onload = function() {alert(reader.result);};
                //     return;
                // }
                var link = document.createElement('a'),
                    filename = 'file.xlsx';
                // if(xhr.getResponseHeader('Content-Disposition')){//filename 
                //     filename = xhr.getResponseHeader('Content-Disposition');
                //     filename=filename.match(/filename="(.*?)"/)[1];
                //     filename=decodeURIComponent(escape(filename));
                // }
                link.href = URL.createObjectURL(data);
                link.download = filename;
                link.click();
            }
        });
        return false;
    });
});
</script>

Optionele functionele functionaliteit wordt gereageerd om het voorbeeld te vereenvoudigen.

Niet nodig om tijdelijke bestanden op de server te maken.

op jQuery v2.2.4 OK. Er is een fout opgetreden op de oude versie:

Uncaught DOMException: Failed to read the 'responseText' property from 'XMLHttpRequest': The value is only accessible if the object's 'responseType' is '' or 'text' (was 'blob').

11

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

12

Ik probeer een CSV-bestand te downloaden en dan iets na het downloaden is voltooid. Dus ik moet een geschikte callback-functie.

Gebruik window.location="..."is geen goed idee omdat ik het programma na het downloaden van de afwerking niet kan gebruiken. Zoiets, verander de kop, dus het is geen goed idee.

fetchis een goed alternatief Echter it kan IE 11 niet ondersteunen. En window.URL.createObjectURLkan niet ondersteunen IE 11. U kunt dit .

Dit is mijn code, het is vergelijkbaar met de code van Shahrukh Alam. Maar u moet ervoor zorgen dat window.URL.createObjectURLMisschien creëert geheugenlekken. U kunt dit . Wanneer reactie is aangekomen, worden gegevens opgeslagen in het geheugen van de browser. Dus voordat u klikt op aLINK, is het bestand gedownload. Het betekent dat je na het downloaden alles kunt doen.

$.ajax({
    url: 'your download url',
    type: 'GET',
}).done(function (data, textStatus, request) {
    // csv => Blob
    var blob = new Blob([data]);
    // the file name from server.
    var fileName = request.getResponseHeader('fileName');
    if (window.navigator && window.navigator.msSaveOrOpenBlob) { // for IE
    window.navigator.msSaveOrOpenBlob(blob, fileName);
    } else { // for others
    var url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    a.download = fileName;
    document.body.appendChild(a);
    a.click();
    window.URL.revokeObjectURL(url);
    //Do something after download 
    ...
    }
}).then(after_download)
}

Antwoord 13

Wat meer dingen toevoegen aan het bovenstaande antwoord voor het downloaden van een bestand

Hieronder staat een Java-springcode die byte-array genereert

@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);
    }

Nu in javascript-code met FileSaver.js, kan een bestand met onderstaande code worden gedownload

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

Het bovenstaande zal het bestand downloaden


Antwoord 14

In Rails doe ik het op deze manier:

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));
    }
   });
 }

De truc is het window.locationgedeelte. De methode van de controller ziet er als volgt uit:

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

Antwoord 15

Gebruik window.openhttps://developer.mozilla.org/en-US/docs/Web/API/Window/open

U kunt deze regel code bijvoorbeeld in een klikhandler plaatsen:

window.open('/file.txt', '_blank');

Het zal een nieuw tabblad openen (vanwege de ‘_blank’ vensternaam) en dat tabblad zal de URL openen.

Uw server-side code zou ook zoiets als dit moeten hebben:

res.set('Content-Disposition', 'attachment; filename=file.txt');

En op die manier zou de browser de gebruiker moeten vragen om het bestand op schijf op te slaan, in plaats van hem alleen het bestand te laten zien. Het sluit ook automatisch het tabblad dat het zojuist heeft geopend.


Antwoord 16

Mijn aanpak is volledig gebaseerd op jQuery. Het probleem voor mij was dat het een POST-HTTP-oproep moest zijn. En ik wilde dat het alleen door jQuery zou worden gedaan.

De oplossing:

$.ajax({
    type: "POST",
    url: "/some/webpage",
    headers: {'X-CSRF-TOKEN': csrfToken},
    data: additionalDataToSend,
    dataType: "text",
    success: function(result) {
        let blob = new Blob([result], { type: "application/octetstream" }); 
        let a = document.createElement('a');
        a.href = window.URL.createObjectURL(blob);
        a.download = "test.xml";;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        window.URL.removeObjectURL(a.href);
        ...
    },
    error: errorDialog
});

Uitleg:

Wat ik en vele anderen doen, zijn om een ​​link op de webpagina te maken, wat aangeeft dat het doelwit moet worden gedownload en het resultaat van het HTTP-verzoek als het doelwit moet worden ingediend. Daarna voeg ik de link toe aan het document dan alleen klikken op de link en het verwijderen van de link achteraf. U hebt geen IFRAME meer nodig.

De magie ligt in de lijnen

let blob = new Blob([result], { type: "application/octetstream" }); 
a.href = window.URL.createObjectURL(blob);

Het interessante punt is dat deze oplossing alleen werkt met een “BLOB “. Zoals je in andere antwoorden kunt zien, gebruiken sommige eenvoudigweg een klodder, maar niet uit te leggen waarom en hoe het te maken.
Zoals je kunt lezen, b.v. In de Mozilla ontwikkelaardocumentatie heb je een bestand nodig, Media Ressource of Blob voor de functie “CreateObjecturl () ” om te werken. Het probleem is dat uw HTTP-reactie geen van die mogelijk is.
Daarom is het eerste dat u moet doen, uw reactie omzetten in een blob. Dit is wat de eerste regel doet. Vervolgens kunt u de “createObjectURL” gebruiken met uw nieuw gemaakte blob.
Als u vervolgens op de link klikt, opent uw browser een dialoogvenster voor het opslaan van bestanden en kunt u uw gegevens opslaan. Uiteraard is het mogelijk dat u geen vaste bestandsnaam kunt definiëren voor uw te downloaden bestand. Dan moet je je antwoord complexer maken, zoals in het antwoord van Luke.

En vergeet niet om geheugen vrij te maken, vooral wanneer u met grote bestanden werkt. Voor meer voorbeelden en informatie kunt u kijken op de details van het JS-blob-object


Antwoord 17

Ok, dus hier is de werkende code bij het gebruik van MVC en je krijgt je bestand van een controller

Laten we zeggen dat u uw bytearray laat declareren en invullen, het enige dat u hoeft te doen is de functie Bestand te gebruiken (met behulp van System.Web.Mvc)

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

en dan, in dezelfde controller, voeg die 2 functies toe

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);
    }

En dan kunt u uw controller bellen om het “succes” of “mislukking” te downloaden

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

18

Ik heb een oplossing gevonden die, terwijl het niet daadwerkelijk AJAX gebruikt, waarmee u een JavaScript-oproep kunt gebruiken om de download aan te vragen en vervolgens een terugbellen te krijgen wanneer de download daadwerkelijk start. Ik vond dit nuttig als de link een server-side-script uitvoert dat een beetje duurt om het bestand te componeren voordat u het verzendt. U kunt dus waarschuwen dat het verwerkt is en wanneer het eindelijk het bestand verzendt, verwijdert u deze verwerkingsmelding. Daarom wilde ik proberen het bestand via Ajax te laden om mee te beginnen, zodat ik een gebeurtenis zou kunnen laten gebeuren wanneer het bestand wordt gevraagd en een ander wanneer het daadwerkelijk begint te downloaden.

De JS op de voorpagina

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

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

Dan het andere bestand:

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

Ik denk dat er een manier is om gegevens te lezen met behulp van JS, dus dan zou geen PHP nodig zijn. Maar ik weet het niet van hand en de server die ik gebruik ondersteunt PHP, dus dit werkt voor mij. dacht dat ik het zou delen voor het geval het iedereen helpt.


19

The HTML Code:-
'<button type="button" id="GetFile">Get File!</button>'
The jQuery Code:-
'$('#GetFile').on('click', function () {
    $.ajax({
        url: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/172905/test.pdf',
        method: 'GET',
        xhrFields: {
            responseType: 'blob'
        },
        success: function (data) {
            var a = document.createElement('a');
            var url = window.URL.createObjectURL(data);
            a.href = url;
            a.download = 'myfile.pdf';
            document.body.append(a);
            a.click();
            a.remove();
            window.URL.revokeObjectURL(url);
        }
    });
});'

Antwoord 20

Als de server het bestand terugschrijft in het antwoord (inclusief cookies als
je gebruikt ze om te bepalen of het downloaden van het bestand is gestart), maak gewoon een formulier met de waarden en verzend het:

function ajaxPostDownload(url, data) {
    var $form;
    if (($form = $('#download_form')).length === 0) {
        $form = $("<form id='download_form'" + " style='display: none; width: 1px; height: 1px; position: absolute; top: -10000px' method='POST' action='" + url + "'></form>");
        $form.appendTo("body");
    }
    //Clear the form fields
    $form.html("");
    //Create new form fields
    Object.keys(data).forEach(function (key) {
        $form.append("<input type='hidden' name='" + key + "' value='" + data[key] + "'>");
    });
    //Submit the form post
    $form.submit();
}

Gebruik:

ajaxPostDownload('/fileController/ExportFile', {
    DownloadToken: 'newDownloadToken',
    Name: $txtName.val(),
    Type: $txtType.val()
});

Controllermethode:

[HttpPost]
public FileResult ExportFile(string DownloadToken, string Name, string Type)
{
    //Set DownloadToken Cookie.
    Response.SetCookie(new HttpCookie("downloadToken", DownloadToken)
    {
        Expires = DateTime.UtcNow.AddDays(1),
        Secure = false
    });
    using (var output = new MemoryStream())
    {
        //get File
        return File(output.ToArray(), "application/vnd.ms-excel", "NewFile.xls");
    }
}

21

Het is zeker dat u het niet via AJAX CALL kunt doen.

Er is echter een oplossing.

Stappen:

Als u Form.Submit () gebruikt voor het downloaden van het bestand, wat u kunt doen is:

  1. Maak een AJAX-oproep van de client naar de server en bewaar de bestandstream in de sessie.
  2. Bij “Succes” die wordt geretourneerd van server, bel uw formulier.Submit () om de bestandstream in de sessie opgeslagen te streamen.

Dit is handig in het geval dat u wilt beslissen of het bestand moet worden gedownload na het maken van formulier.Submit (), bijvoorbeeld: er kan een geval zijn waar op Form.Submit (), een uitzondering op de server optreedt Kant en in plaats van te crashen, moet u mogelijk een aangepast bericht op de clientzijde laten zien, in dat geval kan deze implementatie helpen.


22

Er is een andere oplossing om een ​​webpagina in Ajax te downloaden. Maar ik verwijs naar een pagina die eerst moet worden verwerkt en vervolgens gedownload.

Eerst moet u de paginaverwerking scheiden van de download van de resultaten.

1) Alleen de paginaberekeningen worden gemaakt in de ajax-aanroep.

$.post("CalculusPage.php", { calculusFunction: true, ID: 29, data1: "a", data2: "b" },
    functie(gegevens, status)
    {
      if (status == "succes")
      {
        /* 2) In het antwoord wordt de pagina gedownload die de vorige berekeningen gebruikt. Dit kan bijvoorbeeld een pagina zijn die de resultaten afdrukt van een tabel die is berekend in de ajax-aanroep. */
        window.location.href = DownloadPage.php+"?ID="+29;
      }
    }
);
// Bijvoorbeeld: in de CalculusPage.php
  if ( !empty($_POST["calculusFunction"]) )
  {
    $ID = $_POST["ID"];
    $query = "INVOER IN Voorbeeldpagina (data1, data2) VALUES ('".$_POST["data1"]."', '".$_POST["data2"]."') WHERE id = ".$ID;
    ...
  }
// Bijvoorbeeld: in de DownloadPage.php
  $ID = $_GET["ID"];
  $sede = "SELECTEER * VAN Voorbeeldpagina WHERE id = ".$ID;
  ...
  $filename="Export_Data.xls";
  header("Inhoudstype: application/vnd.ms-excel");
  header("Content-Disposition: inline; bestandsnaam=$bestandsnaam");
  ...

Ik hoop dat deze oplossing voor velen nuttig kan zijn, net als voor mij.


Antwoord 23

Dat is dat het zo goed werkt in elke browser (ik gebruik asp.net core)

           function onDownload() {
  const api = '@Url.Action("myaction", "mycontroller")'; 
  var form = new FormData(document.getElementById('form1'));
  fetch(api, { body: form, method: "POST"})
      .then(resp => resp.blob())
      .then(blob => {
          const url = window.URL.createObjectURL(blob);
        $('#linkdownload').attr('download', 'Attachement.zip');
          $('#linkdownload').attr("href", url);
          $('#linkdownload')
              .fadeIn(3000,
                  function() { });
      })
      .catch(() => alert('An error occurred'));
}

 <button type="button" onclick="onDownload()" class="btn btn-primary btn-sm">Click to Process Files</button>
 <a role="button" href="#" style="display: none" class="btn btn-sm btn-secondary" id="linkdownload">Click to download Attachments</a>
 <form asp-controller="mycontroller" asp-action="myaction" id="form1"></form>
 

24

Ik worstelde al heel lang met dit probleem. Uiteindelijk suggereerde een elegante externe bibliotheek hier heeft me eruit geholpen.

Other episodes