So laden Sie Dateien mit Axios herunter

113

Ich verwende Axios für grundlegende http-Anfragen wie GET und POST und es funktioniert gut. Jetzt muss ich auch Excel-Dateien herunterladen können. Ist das mit Axios möglich? Wenn ja, hat jemand einen Beispielcode? Wenn nicht, was kann ich sonst noch in einer React-Anwendung verwenden, um dasselbe zu tun?

David Choi
quelle
Mit dieser Lösung können wir die Excel-Datei herunterladen. stackoverflow.com/questions/57127361/…
Md. Nazrul Islam

Antworten:

100

Wenn die Antwort mit einer herunterladbaren Datei geliefert wird, sind die Antwort-Header ungefähr so

Content-Disposition: "attachment;filename=report.xls"
Content-Type: "application/octet-stream" // or Content-type: "application/vnd.ms-excel"

Sie können eine separate Komponente erstellen, die einen versteckten Iframe enthält.

  import * as React from 'react';

  var MyIframe = React.createClass({

     render: function() {
         return (
           <div style={{display: 'none'}}>
               <iframe src={this.props.iframeSrc} />
           </div>
         );
     }
  });

Jetzt können Sie die URL der herunterladbaren Datei als Requisite an diese Komponente übergeben. Wenn diese Komponente also eine Requisite erhält, wird sie erneut gerendert und die Datei wird heruntergeladen.

Bearbeiten: Sie können auch das Modul js-file-download verwenden . Link zum Github Repo

const FileDownload = require('js-file-download');

Axios({
  url: 'http://localhost/downloadFile',
  method: 'GET',
  responseType: 'blob', // Important
}).then((response) => {
    FileDownload(response.data, 'report.csv');
});

Hoffe das hilft :)

Hardik Modha
quelle
1
Vielen Dank. Kannst du mir sagen, ob dies im Ajax-Stil ist? Es wäre gut, die Seite nicht zu blockieren.
David Choi
Ja, die Seite wird nicht blockiert. Wenn Sie die URL als Requisite an diese Komponente übergeben, wird die Datei automatisch heruntergeladen. Sie müssen nichts tun.
Hardik Modha
Noch eine Frage. In meinem Fall wird die heruntergeladene Datei dynamisch mit einigen übergebenen Parametern erstellt. Es hat also nicht wirklich einen einheitlichen Standort. Welche URL sende ich für diese Art von Szenario? Zum Beispiel, wenn ich axios.post ('api / getmyexcelfile', params) aufgerufen habe;
David Choi
Wie in dieser Antwort erwähnt. Im Axios-Antwortobjekt befindet sich innerhalb der Anforderung ein Feld mit dem Namen As. Möglicherweise ist responseURLdies die gewünschte URL.
Hardik Modha
1
Ich folgte diesem und konnte die Datei herunterladen. Aber die Datei ist kaputt (funktioniert nicht). Wenn ich jedoch die Umleitung (window.location.href) verwende, wird die Datei heruntergeladen und funktioniert einwandfrei. Kann mir bitte jemand dabei helfen? ( stackoverflow.com/questions/56306008/… )
Thidasa Pankaja
118

Eine allgemeinere Lösung

axios({
  url: 'http://api.dev/file-download', //your url
  method: 'GET',
  responseType: 'blob', // important
}).then((response) => {
   const url = window.URL.createObjectURL(new Blob([response.data]));
   const link = document.createElement('a');
   link.href = url;
   link.setAttribute('download', 'file.pdf'); //or any other extension
   document.body.appendChild(link);
   link.click();
});

Überprüfen Sie die Macken unter https://gist.github.com/javilobo8/097c30a233786be52070986d8cdb1743

Volle Credits an: https://gist.github.com/javilobo8

Weinberg
quelle
11
Vielen Dank für die Lösung. Nur ein paar Hinweise für andere: Dies funktioniert zwar für viele Anwendungsfälle, aber für große Dateien können Sie den Download-Fortschritt nicht sehen. Und es wird zusätzlichen Speicher im Browser benötigen. Wie in anderen Lösungen angedeutet, aber nicht dargelegt, besteht der allgemeine Ansatz darin, die Überschrift "Inhaltsdisposition: Anhang" zu verwenden. Der Browser behandelt es daher als nativen Download (oben genannter Download-Fortschritt + direkter Download auf die Festplatte).
John Lee
Auf der Serverseite scheint der Download-Fortschritt nicht zulässig zu sein, selbst wenn ich den Content-Desposition-Header festgelegt habe.
Huggie
4
Danke dafür. Ich habe mich gefragt, warum der Dateiinhalt nicht richtig angezeigt wird. Es stellte sich heraus, dass ich vermisst wurderesponseType: 'blob'
AliAvci
Lädt dies die Datei nicht zuerst als Antwort auf den Speicher herunter (ohne dass der Browser tatsächlich den Download-Fortschritt anzeigt), nur wenn die Datei als Blob im Speicher heruntergeladen wird, dann versucht nur der Browser, sie in der Download-Datei zu speichern.
Ricky -U
@ Ricky-U Ja, Sie haben Recht, die xhr-Anfrage wird gesendet und wenn die Antwort eintrifft, wird sie im Speicher gepuffert und später responsenach Abschluss in einer Variablen gespeichert . Dann createObjectURLerstellt eine lokale URL auf diese Daten , dass ein <a> navigieren.
Viney
48

Herunterladen von Dateien (mit Axios und Sicherheit)

Dies ist sogar noch komplexer, wenn Sie Dateien mit Axios und einigen Sicherheitsmaßnahmen herunterladen möchten. Um zu verhindern, dass andere zu viel Zeit damit verbringen, dies herauszufinden, möchte ich Sie durch diese Sache führen.

Sie müssen 3 Dinge tun:

1. Configure your server to permit the browser to see required HTTP headers
2. Implement the server-side service, and making it advertise the correct file type for the downloaded file.
3. Implementing an Axios handler to trigger a FileDownload dialog within the browser

Diese Schritte sind größtenteils machbar - werden jedoch durch die Beziehung des Browsers zu CORS erheblich erschwert. Ein Schritt auf einmal:

1. Konfigurieren Sie Ihren (HTTP-) Server

Bei Verwendung der Transportsicherheit kann JavaScript, das in einem Browser ausgeführt wird, [beabsichtigt] nur auf 6 der vom HTTP-Server tatsächlich gesendeten HTTP-Header zugreifen. Wenn der Server einen Dateinamen für den Download vorschlagen soll, müssen wir den Browser darüber informieren, dass JavaScript "OK" ist, um Zugriff auf andere Header zu erhalten, in denen der vorgeschlagene Dateiname transportiert wird.

Nehmen wir zur Diskussion an, dass der Server den vorgeschlagenen Dateinamen in einem HTTP-Header namens X-Suggested-Filename übertragen soll . Der HTTP-Server teilt dem Browser mit, dass es in Ordnung ist , diesen empfangenen benutzerdefinierten Header für JavaScript / Axios mit dem folgenden Header verfügbar zu machen:

Access-Control-Expose-Headers: X-Suggested-Filename

Die genaue Konfiguration Ihres HTTP-Servers zum Festlegen dieses Headers variiert von Produkt zu Produkt.

Eine vollständige Erläuterung und detaillierte Beschreibung dieser Standardheader finden Sie unter https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers .

2. Implementieren Sie den serverseitigen Dienst

Ihre serverseitige Service-Implementierung muss jetzt zwei Dinge ausführen:

1. Create the (binary) document and assign correct ContentType to the response
2. Assign the custom header (X-Suggested-Filename) containing the suggested file name for the client

Dies erfolgt je nach gewähltem Technologie-Stack auf unterschiedliche Weise. Ich werde ein Beispiel mit dem JavaEE 7-Standard skizzieren, das einen Excel-Bericht ausgeben soll:

@GET
@Path("/report/excel")
@Produces("application/vnd.ms-excel")
public Response getAllergyAndPreferencesReport() {

    // Create the document which should be downloaded
    final byte[] theDocumentData = .... 

    // Define a suggested filename
    final String filename = ... 

    // Create the JAXRS response
    // Don't forget to include the filename in 2 HTTP headers: 
    //
    // a) The standard 'Content-Disposition' one, and
    // b) The custom 'X-Suggested-Filename'  
    //
    final Response.ResponseBuilder builder = Response.ok(
            theDocumentData, "application/vnd.ms-excel")
            .header("X-Suggested-Filename", fileName);
    builder.header("Content-Disposition", "attachment; filename=" + fileName);

    // All Done.
    return builder.build();
}

Der Dienst gibt jetzt das Binärdokument aus (in diesem Fall einen Excel-Bericht), legt den richtigen Inhaltstyp fest und sendet außerdem einen benutzerdefinierten HTTP-Header mit dem vorgeschlagenen Dateinamen, der beim Speichern des Dokuments verwendet werden soll.

3. Implementieren Sie einen Axios-Handler für das empfangene Dokument

Hier gibt es einige Fallstricke. Stellen Sie daher sicher, dass alle Details korrekt konfiguriert sind:

  1. Der Dienst antwortet auf @GET (dh HTTP GET), daher muss der Axios-Aufruf 'axios.get (...)' sein.
  2. Das Dokument wird als Bytestrom übertragen. Sie müssen axios daher anweisen, die Antwort als HTML5-Blob zu behandeln. (Dh Antworttyp: 'Blob' ).
  3. In diesem Fall wird die JavaScript-Bibliothek zum Speichern von Dateien verwendet, um das Browserdialogfeld zu öffnen. Sie könnten jedoch eine andere wählen.

Die Axios-Implementierung des Skeletts wäre dann wie folgt:

 // Fetch the dynamically generated excel document from the server.
 axios.get(resource, {responseType: 'blob'}).then((response) => {

    // Log somewhat to show that the browser actually exposes the custom HTTP header
    const fileNameHeader = "x-suggested-filename";
    const suggestedFileName = response.headers[fileNameHeader];'
    const effectiveFileName = (suggestedFileName === undefined
                ? "allergierOchPreferenser.xls"
                : suggestedFileName);
    console.log("Received header [" + fileNameHeader + "]: " + suggestedFileName
                + ", effective fileName: " + effectiveFileName);

    // Let the user save the file.
    FileSaver.saveAs(response.data, effectiveFileName);

    }).catch((response) => {
        console.error("Could not Download the Excel report from the backend.", response);
    });
Lennart Jörelid
quelle
20
Was ist "FileSaver"?
Hauptkumpel
6
Es ist eine Bibliothek für Download-Dateien, github.com/eligrey/FileSaver.js/#filesaverjs
Radi
2
Dies funktioniert, es wird jedoch empfohlen, content-dispositionanstelle von Header zu verwenden x-suggested-filename.
Rosdi Kasim
13

Axios.post-Lösung mit IE und anderen Browsern

Ich habe hier einige unglaubliche Lösungen gefunden. Probleme mit dem IE-Browser werden jedoch häufig nicht berücksichtigt. Vielleicht spart es jemand anderem etwas Zeit.

 axios.post("/yourUrl"
                , data,
                {responseType: 'blob'}
            ).then(function (response) {
                    let fileName = response.headers["content-disposition"].split("filename=")[1];
                    if (window.navigator && window.navigator.msSaveOrOpenBlob) { // IE variant
                        window.navigator.msSaveOrOpenBlob(new Blob([response.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}),
                            fileName);
                    } else {
                        const url = window.URL.createObjectURL(new Blob([response.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}));
                        const link = document.createElement('a');
                        link.href = url;
                        link.setAttribute('download', response.headers["content-disposition"].split("filename=")[1]);
                        document.body.appendChild(link);
                        link.click();
                    }
                }
            );

Das obige Beispiel gilt für Excel-Dateien, kann jedoch mit geringen Änderungen auf jedes Format angewendet werden.

Und auf dem Server habe ich dies getan, um eine Excel-Datei zu senden.

response.contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"

response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=exceptions.xlsx")
Alex
quelle
8
        axios.get(
            '/app/export'
        ).then(response => {    
            const url = window.URL.createObjectURL(new Blob([response]));
            const link = document.createElement('a');
            link.href = url;
            const fileName = `${+ new Date()}.csv`// whatever your file name .
            link.setAttribute('download', fileName);
            document.body.appendChild(link);
            link.click();
            link.remove();// you need to remove that elelment which is created before.
})
Nitin.
quelle
8

Die Funktion zum Ausführen des API-Aufrufs mit axios:

  function getFileToDownload (apiUrl) {
     return axios.get(apiUrl, {
       responseType: 'arraybuffer',
       headers: {
         'Content-Type': 'application/json'
       }
     })
  }

Rufen Sie die Funktion auf und laden Sie die Excel-Datei herunter, die Sie erhalten:

getFileToDownload('putApiUrlHere')
  .then (response => {
      const type = response.headers['content-type']
      const blob = new Blob([response.data], { type: type, encoding: 'UTF-8' })
      const link = document.createElement('a')
      link.href = window.URL.createObjectURL(blob)
      link.download = 'file.xlsx'
      link.click()
  })
roli roli
quelle
6

Es ist sehr einfacher Javascript-Code, um einen Download für den Benutzer auszulösen:

window.open("<insert URL here>")

Sie möchten / brauchen keine Axios für diese Operation. Es sollte Standard sein, den Browser einfach das tun zu lassen.

Hinweis: Wenn Sie eine Autorisierung für den Download benötigen, funktioniert dies möglicherweise nicht. Ich bin mir ziemlich sicher, dass Sie Cookies verwenden können, um eine solche Anfrage zu autorisieren, vorausgesetzt, sie befindet sich in derselben Domain, aber in einem solchen Fall funktioniert dies möglicherweise nicht sofort.


Ob es möglich ist ... nicht mit dem eingebauten Mechanismus zum Herunterladen von Dateien, nein .

Multihunter
quelle
12
Autorisierungsheader?
Ejaz Karim
Was ist, wenn Sie einen Token senden müssen?
user3808307
Wenn Sie den Server steuern, können Sie das Zugriffstoken einfach als Cookie speichern, und der Browser fügt es jeder Anforderung an Ihren Server hinzu. medium.com/@ryanchenkie_40935/…
Multihunter
Dies kann nur verwendet werden, wenn es sich um ein GET handelt, oder?
Charith Jayasanka
1
@CharithJayasanka Ja, ich glaube schon.
Multihunter
2

Der Trick besteht darin, ein unsichtbares Ankertag im zu erstellen und eine Reaktion render()hinzuzufügen, die es refermöglicht, einen Klick auszulösen, sobald wir die Axios-Antwort erhalten haben:

class Example extends Component {
    state = {
        ref: React.createRef()
    }

    exportCSV = () => {
        axios.get(
            '/app/export'
        ).then(response => {
            let blob = new Blob([response.data], {type: 'application/octet-stream'})
            let ref = this.state.ref
            ref.current.href = URL.createObjectURL(blob)
            ref.current.download = 'data.csv'
            ref.current.click()
        })
    }

    render(){
        return(
            <div>
                <a style={{display: 'none'}} href='empty' ref={this.state.ref}>ref</a>
                <button onClick={this.exportCSV}>Export CSV</button>
            </div>
        )
    }
}

Hier ist die Dokumentation: https://reactjs.org/docs/refs-and-the-dom.html . Eine ähnliche Idee finden Sie hier: https://thewebtier.com/snippets/download-files-with-axios/ .

Enjolrasyn
quelle
-1

Für Axios POST - Anforderung sollte die Anfrage so etwas wie diese: Der Schlüssel hier ist , dass die responseTypeund headerFelder in dem 3. Parameter des Eintrages sein muss. Der 2. Parameter sind die Anwendungsparameter.

export const requestDownloadReport = (requestParams) => async dispatch => { 
  let response = null;
  try {
    response = await frontEndApi.post('createPdf', {
      requestParams: requestParams,
    },
    {
      responseType: 'arraybuffer', // important...because we need to convert it to a blob. If we don't specify this, response.data will be the raw data. It cannot be converted to blob directly.
      headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/pdf'
      }
  });          
  }
  catch(err) {
    console.log('[requestDownloadReport][ERROR]', err);
    return err
  }

  return response;
}
remondo
quelle
-4

Meine Antwort ist ein totaler Hack - ich habe gerade einen Link erstellt, der wie eine Schaltfläche aussieht, und die URL dazu hinzugefügt.

<a class="el-button"
  style="color: white; background-color: #58B7FF;"
  :href="<YOUR URL ENDPOINT HERE>"
  :download="<FILE NAME NERE>">
<i class="fa fa-file-excel-o"></i>&nbsp;Excel
</a>

Ich verwende die hervorragenden VueJs, daher die seltsamen Anotationen. Diese Lösung ist jedoch rahmenunabhängig. Die Idee würde für jedes HTML-basierte Design funktionieren.

Anthony
quelle