node.js Axios Download-Dateistream und WriteFile

Lesezeit: 8 Minuten

Benutzeravatar von ar099968
ar099968

Ich möchte eine pdf-Datei mit herunterladen axios und auf Platte (serverseitig) mit speichern fs.writeFileIch habe versucht:

axios.get('https://xxx/my.pdf', {responseType: 'blob'}).then(response => {
    fs.writeFile('/temp/my.pdf', response.data, (err) => {
        if (err) throw err;
        console.log('The file has been saved!');
    });
});

Die Datei wird gespeichert, aber der Inhalt ist beschädigt …

Wie speichere ich die Datei richtig?

  • Sie erhalten das Konsolenprotokoll “Die Datei wurde gespeichert” und die Datei wird erstellt und nur der Inhalt ist falsch?

    – Roland Starke

    27. März 2019 um 10:19 Uhr


  • Wo rufst du axios.get auf? es wird nicht darauf gewartet, dass die Datei geschrieben wird. Versprechen Sie besser die fs oder verwenden Sie fs-extra oder verwenden Sie versprochene Methoden von fs. und verwenden Sie wie return fs.writeFile(…)

    – AZ_

    27. März 2019 um 10:21 Uhr


  • @RolandStarke ja, die Datei wird gespeichert

    – ar099968

    27. März 2019 um 10:27 Uhr

  • Ich habe unten einen saubereren Ansatz zur Lösung des Problems mit Node-Stream-Pipelines veröffentlicht. Es basiert auf demselben Konzept, das die akzeptierte Antwort vorschlägt. stackoverflow.com/a/64925465/3476378

    – Aman Saraf

    20. November 2020 um 7:39 Uhr


Benutzeravatar von csotiriou
csotiriou

Tatsächlich glaube ich, dass die zuvor akzeptierte Antwort einige Mängel aufweist, da sie den Writestream nicht richtig verarbeitet. Wenn Sie also “then()” aufrufen, nachdem Axios Ihnen die Antwort gegeben hat, erhalten Sie am Ende eine teilweise heruntergeladene Datei.

Dies ist eine geeignetere Lösung, wenn Sie etwas größere Dateien herunterladen:

export async function downloadFile(fileUrl: string, outputLocationPath: string) {
  const writer = createWriteStream(outputLocationPath);

  return Axios({
    method: 'get',
    url: fileUrl,
    responseType: 'stream',
  }).then(response => {

    //ensure that the user can call `then()` only when the file has
    //been downloaded entirely.

    return new Promise((resolve, reject) => {
      response.data.pipe(writer);
      let error = null;
      writer.on('error', err => {
        error = err;
        writer.close();
        reject(err);
      });
      writer.on('close', () => {
        if (!error) {
          resolve(true);
        }
        //no need to call the reject here, as it will have been called in the
        //'error' stream;
      });
    });
  });
}

Auf diese Weise können Sie anrufen downloadFile()Anruf then() auf das zurückgegebene Versprechen und stellen Sie sicher, dass die heruntergeladene Datei vollständig verarbeitet wurde.

Wenn Sie eine modernere Version von NodeJS verwenden, können Sie stattdessen Folgendes versuchen:

import * as stream from 'stream';
import { promisify } from 'util';

const finished = promisify(stream.finished);

export async function downloadFile(fileUrl: string, outputLocationPath: string): Promise<any> {
  const writer = createWriteStream(outputLocationPath);
  return Axios({
    method: 'get',
    url: fileUrl,
    responseType: 'stream',
  }).then(response => {
    response.data.pipe(writer);
    return finished(writer); //this is a Promise
  });
}

  • Das ist richtig und löst genau das Problem im Zusammenhang mit Partial data error

    – Giorgio Andretti

    27. April 2020 um 13:12 Uhr

  • Dies sollte die akzeptierte Antwort sein. Es hat den teilweisen Download-Fehler behoben

    – Arizona

    12. Mai 2020 um 18:10 Uhr

  • Ich habe unten einen saubereren Ansatz zum gleichen Konzept Ihrer Verwendung von Stream-Pipelines veröffentlicht: stackoverflow.com/a/64925465/3476378.

    – Aman Saraf

    20. November 2020 um 7:38 Uhr

  • Ich bin mir nicht sicher, ob ich folgen kann. Wenn Bytes heruntergeladen werden, werden sie in eine Datei gestreamt, und sobald alle Bytes gestreamt wurden, endet das Promise und der Rest des Anwendungsablaufs wird fortgesetzt. Das ‘then’ im Beispiel wird aufgerufen, bevor die Datei vollständig heruntergeladen wurde – sehen Sie in der Dokumentation nach stream AntwortTyp von Axios.

    – csotiriou

    27. Februar 2021 um 22:17 Uhr

  • response.data.pipe ist keine Funktion

    – rendom

    12. Juni 2021 um 5:56 Uhr

Sie können einfach verwenden response.data.pipe und fs.createWriteStream um die Antwort an die Datei weiterzuleiten

axios({
    method: "get",
    url: "https://xxx/my.pdf",
    responseType: "stream"
}).then(function (response) {
    response.data.pipe(fs.createWriteStream("/temp/my.pdf"));
});

  • Ich danke dir sehr!! Habe ewig danach gesucht

    – Harrison Cramer

    26. Februar 2020 um 1:16 Uhr

  • Diese Antwort ist nicht vollständig, denn wenn Sie einige größere Dateien herunterladen, gibt Ihnen die Pipe mehr als ein Ereignis. Dieser Code wartet nicht, bis die gesamte Datei heruntergeladen wurde, bevor man anrufen kann then darauf. Werfen Sie einen Blick auf meine Lösung, um herauszufinden, was ich für eine vollständigere Lösung halte.

    – csotiriou

    17. April 2020 um 10:33 Uhr

  • response.data.pipe ist keine Funktion

    – Murat Serdar Akkuş

    11. Juni 2020 um 1:36 Uhr

  • Wenn die Datei nicht auf den lokalen Speicher heruntergeladen werden soll, wie das geht, habe ich res.sendFile in node.js ausprobiert

    – sj

    16. April 2021 um 8:06 Uhr

  • Um diese Lösung zu kritisieren, Sie muss setze den responseType auf „stream“. Andernfalls wird ein Fehler verursacht, wenn Sie versuchen, es an einen anderen Stream weiterzuleiten.

    – Rashad Rivera

    Vor 17 Stunden

Benutzeravatar von Aman Saraf
Aman Saraf

Das Problem mit beschädigten Dateien liegt an Gegendruck in Knotenströmen. Vielleicht finden Sie diesen Link hilfreich zum Lesen: https://nodejs.org/es/docs/guides/backpressuring-in-streams/

Ich bin nicht wirklich ein Fan der Verwendung von deklarativen Promise-Basisobjekten in JS-Codes, da ich der Meinung bin, dass dies die eigentliche Kernlogik verschmutzt und den Code schwer lesbar macht. Darüber hinaus müssen Sie Ereignishandler und Listener bereitstellen, um sicherzustellen, dass der Code vollständig ist.

Ein saubererer Ansatz auf der gleichen Logik, die die akzeptierte Antwort vorschlägt, ist unten angegeben. Es verwendet die Konzepte von Stream-Pipelines.

const util = require('util');
const stream = require('stream');
const pipeline = util.promisify(stream.pipeline);

const downloadFile = async () => {
  try {
    const request = await axios.get('https://xxx/my.pdf', {
      responseType: 'stream',
    });
    await pipeline(request.data, fs.createWriteStream('/temp/my.pdf'));
    console.log('download pdf pipeline successful');   
  } catch (error) {
    console.error('download pdf pipeline failed', error);
  }
}

exports.downloadFile = downloadFile

Ich hoffe, Sie finden das nützlich.

  • Warum Antworttyp Blob und nicht Stream?

    – 1252748

    26. Februar 2021 um 1:54 Uhr

  • Bei dieser Methode erhalte ich den Fehler „stream.on ist keine Funktion“.

    – dz210

    7. Juni 2021 um 1:11 Uhr

  • Ich habe es so zum Laufen gebracht: const resp = await axios.get(….); warten Sie auf die Pipeline (bzw. Daten, fs.createWriteStream (…))

    – dz210

    7. Juni 2021 um 3:28 Uhr


  • @1252748 Blob ist nur eine Browseroption.

    – B45i

    27. November 2021 um 10:27 Uhr

Benutzeravatar von Armand
Armand

// This works perfectly well! 
const axios = require('axios'); 

axios.get('http://www.sclance.com/pngs/png-file-download/png_file_download_1057991.png', {responseType: "stream"} )  
.then(response => {  
// Saving file to working directory  
    response.data.pipe(fs.createWriteStream("todays_picture.png"));  
})  
    .catch(error => {  
    console.log(error);  
});  

Benutzeravatar von fedesc
Fed

Knoten Dateisystem writeFile codiert Daten standardmäßig in UTF8. was in deinem Fall ein Problem sein könnte.

Versuchen Sie, Ihre Codierung auf einzustellen null und überspringen Sie die Codierung der empfangenen Daten:

fs.writeFile('/temp/my.pdf', response.data, {encoding: null}, (err) => {...}

Sie können die Codierung auch als Zeichenfolge (anstelle des Optionsobjekts) dekalieren, wenn Sie nur die Codierung und keine anderen Optionen deklarieren. Zeichenfolge wird als Kodierungswert behandelt. als solche:

fs.writeFile('/temp/my.pdf', response.data, 'null', (err) => {...}

mehr einlesen fileSystem API write_file

  • Während dieser Code die Frage lösen kann, inklusive Erklärung wie und warum dies das Problem löst, würde wirklich dazu beitragen, die Qualität Ihres Beitrags zu verbessern, und wahrscheinlich zu mehr Up-Votes führen. Denken Sie daran, dass Sie die Frage für zukünftige Leser beantworten, nicht nur für die Person, die jetzt fragt. Bitte bearbeiten Sie Ihre Antwort, um Erklärungen hinzuzufügen und einen Hinweis darauf zu geben, welche Einschränkungen und Annahmen gelten.

    – Doppel-Piep

    27. März 2019 um 11:42 Uhr

  • @double-beep tnx für deinen Kommentar. Ich habe mit einigen Erklärungen bearbeitet und Material gelesen node fileSystem API über die WriteFile-Funktion. 🙂

    – Föderal

    27. März 2019 um 11:56 Uhr

Benutzeravatar von levy9527
Abgabe9527

Ich habe versucht, und ich bin sicher, dass mit response.data.pipe und fs.createWriteStream kann arbeiten.


Außerdem möchte ich meine Situation und Lösung hinzufügen

Lage:

  • verwenden koa um einen node.js-Server zu entwickeln
  • verwenden axios um ein pdf über url zu erhalten
  • verwenden pdf-parse um das pdf zu analysieren
  • Extrahieren Sie einige Informationen aus PDF und geben Sie sie als JSON an den Browser zurück

Lösung:

const Koa = require('koa');
const app = new Koa();
const axios = require('axios')
const fs = require("fs")
const pdf = require('pdf-parse');
const utils = require('./utils')

app.listen(process.env.PORT || 3000)

app.use(async (ctx, next) => {
      let url="https://path/name.pdf"
      let resp = await axios({
          url: encodeURI(url),
          responseType: 'arraybuffer'
        })

        let data = await pdf(resp.data)

        ctx.body = {
            phone: utils.getPhone(data.text),
            email: utils.getEmail(data.text),
        }
})

Bei dieser Lösung muss keine Datei geschrieben und gelesen werden, es ist effizienter.

  • Während dieser Code die Frage lösen kann, inklusive Erklärung wie und warum dies das Problem löst, würde wirklich dazu beitragen, die Qualität Ihres Beitrags zu verbessern, und wahrscheinlich zu mehr Up-Votes führen. Denken Sie daran, dass Sie die Frage für zukünftige Leser beantworten, nicht nur für die Person, die jetzt fragt. Bitte bearbeiten Sie Ihre Antwort, um Erklärungen hinzuzufügen und einen Hinweis darauf zu geben, welche Einschränkungen und Annahmen gelten.

    – Doppel-Piep

    27. März 2019 um 11:42 Uhr

  • @double-beep tnx für deinen Kommentar. Ich habe mit einigen Erklärungen bearbeitet und Material gelesen node fileSystem API über die WriteFile-Funktion. 🙂

    – Föderal

    27. März 2019 um 11:56 Uhr

Benutzeravatar von Lorenzo Regalado
Lorenzo Regalado

Der folgende Code entnommen aus https://gist.github.com/senthilmpro/072f5e69bdef4baffc8442c7e696f4eb?permalink_comment_id=3620639#gistcomment-3620639 hat bei mir funktioniert

const res = await axios.get(url, { responseType: 'arraybuffer' });
fs.writeFileSync(downloadDestination, res.data);

1430760cookie-checknode.js Axios Download-Dateistream und WriteFile

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy