ar099968
quiero descargar un archivo pdf con axios
y guardar en el disco (lado del servidor) con fs.writeFile
Yo he tratado:
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!');
});
});
el archivo se guarda pero el contenido está roto…
¿Cómo guardo correctamente el archivo?
csotiriou
En realidad, creo que la respuesta previamente aceptada tiene algunas fallas, ya que no manejará el flujo de escritura correctamente, por lo que si llama “entonces ()” después de que Axios le haya dado la respuesta, terminará con un archivo parcialmente descargado.
Esta es una solución más apropiada cuando se descargan archivos un poco más grandes:
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;
});
});
});
}
De esta manera, puede llamar downloadFile()
llamar then()
en la promesa devuelta, y asegurándose de que el archivo descargado haya completado el procesamiento.
O, si usa una versión más moderna de NodeJS, puede probar esto en su lugar:
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
});
}
-
Esto es correcto y resuelve exactamente el problema relacionado con el error de datos parciales
– Giorgio Andreti
27 de abril de 2020 a las 13:12
-
esta debería ser la respuesta aceptada. corrigió el error de descarga parcial
– ariezona
12 mayo 2020 a las 18:10
-
He publicado un enfoque más limpio sobre el mismo concepto de usar canalizaciones de transmisión a continuación: stackoverflow.com/a/64925465/3476378.
– Amán Saraf
20 de noviembre de 2020 a las 7:38
-
No estoy seguro de seguir. A medida que se descargan los bytes, se transmiten a un archivo y, una vez que se han transmitido todos los bytes, la Promesa finaliza y el resto del flujo de la aplicación continúa. El ‘entonces’ en el ejemplo se llama antes de que el archivo haya terminado de descargarse; consulte la documentación sobre el
stream
tipo de respuesta de axios.– csotiriou
27 de febrero de 2021 a las 22:17
-
response.data.pipe no es una función
– azar
12 de junio de 2021 a las 5:56
Simplemente puede usar response.data.pipe
y fs.createWriteStream
canalizar la respuesta al archivo
axios({
method: "get",
url: "https://xxx/my.pdf",
responseType: "stream"
}).then(function (response) {
response.data.pipe(fs.createWriteStream("/temp/my.pdf"));
});
-
¡¡Muchas gracias!! Estaba buscando esto para siempre
– Harrison Cramer
26 de febrero de 2020 a las 1:16
-
Esta respuesta no está completa, porque cuando descarga algunos archivos más grandes, la tubería le dará más de un evento. Este código no espera hasta que se haya descargado todo el archivo antes de poder llamar
then
en eso. Eche un vistazo a mi solución para encontrar lo que considero una solución más completa.– csotiriou
17 de abril de 2020 a las 10:33
-
response.data.pipe no es una función
– Murat Serdar Akkuş
11 de junio de 2020 a las 1:36
-
si no se descarga el archivo en el almacenamiento local, entonces cómo hacerlo, probé res.sendFile en node.js
– sj
16 de abril de 2021 a las 8:06
-
Para criticar esta solución, usted deber establezca el tipo de respuesta en “flujo”. Si no lo hace, se producirá un error cuando intente canalizarlo a otra secuencia.
– Rashad Rivera
21 oct a las 15:02
Amán Saraf
El problema con el archivo roto se debe a contrapresión en flujos de nodos. Puede encontrar este enlace útil para leer: https://nodejs.org/es/docs/guides/backpressuring-in-streams/
No soy realmente un fanático del uso de objetos declarativos básicos de Promise en códigos JS, ya que siento que contamina la lógica central real y hace que el código sea difícil de leer. Además, debe aprovisionar controladores y oyentes de eventos para asegurarse de que el código esté completo.
A continuación se proporciona un enfoque más limpio sobre la misma lógica que propone la respuesta aceptada. Utiliza los conceptos de tuberías de corriente.
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
Espero que encuentres esto útil.
-
¿Por qué la respuesta escribe blob y no transmite?
– 1252748
26 de febrero de 2021 a las 1:54
-
Recibo el error “stream.on no es una función” con este método
– dz210
7 de junio de 2021 a las 1:11
-
Lo tengo funcionando así: const resp = await axios.get(….); esperar canalización (resp.data, fs.createWriteStream(…))
– dz210
7 de junio de 2021 a las 3:28
-
@ 1252748 blob es una opción solo para navegador.
– B45i
27 de noviembre de 2021 a las 10:27
Armando
// 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);
});
federal
sistema de archivos de nodo writeFile
codifica los datos de forma predeterminada en UTF8. que podría ser un problema en su caso.
Intente configurar su codificación en null
y omita la codificación de los datos recibidos:
fs.writeFile('/temp/my.pdf', response.data, {encoding: null}, (err) => {...}
también puede decalre la codificación como una cadena (en lugar de un objeto de opciones) si solo declara la codificación y ninguna otra opción. la cadena se manejará como valor de codificación. como tal:
fs.writeFile('/temp/my.pdf', response.data, 'null', (err) => {...}
más leer en fileSystem API write_file
-
Si bien este código puede resolver la pregunta, incluyendo una explicación de cómo y por qué esto resuelve el problema realmente ayudaría a mejorar la calidad de su publicación y probablemente resulte en más votos a favor. Recuerda que estás respondiendo la pregunta para lectores en el futuro, no solo para la persona que pregunta ahora. Edite su respuesta para agregar explicaciones y dar una indicación de las limitaciones y suposiciones que se aplican.
– doble pitido
27 de marzo de 2019 a las 11:42
-
@Double-beep tnx por su comentario. He editado con alguna explicación y leído material de
node fileSystem API
sobre la función writeFile. 🙂– federal
27 de marzo de 2019 a las 11:56
lorenzo regalado
El siguiente código tomado de https://gist.github.com/senthilmpro/072f5e69bdef4baffc8442c7e696f4eb?permalink_comment_id=3620639#gistcomment-3620639 trabajó para mi
const res = await axios.get(url, { responseType: 'arraybuffer' });
fs.writeFileSync(downloadDestination, res.data);
-
Si bien este código puede resolver la pregunta, incluyendo una explicación de cómo y por qué esto resuelve el problema realmente ayudaría a mejorar la calidad de su publicación y probablemente resulte en más votos a favor. Recuerda que estás respondiendo la pregunta para lectores en el futuro, no solo para la persona que pregunta ahora. Edite su respuesta para agregar explicaciones y dar una indicación de las limitaciones y suposiciones que se aplican.
– doble pitido
27 de marzo de 2019 a las 11:42
-
@Double-beep tnx por su comentario. He editado con alguna explicación y leído material de
node fileSystem API
sobre la función writeFile. 🙂– federal
27 de marzo de 2019 a las 11:56
impuesto9527
Lo he intentado, y estoy seguro de que usando response.data.pipe
y fs.createWriteStream
puede trabajar.
Además, quiero agregar mi situación y solución.
Situación:
- usando
koa
para desarrollar un servidor node.js - usando
axios
para obtener un pdf a través de url - usando
pdf-parse
para analizar el pdf - extraiga información de pdf y devuélvala como json al navegador
Solución:
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),
}
})
En esta solución, no necesita escribir y leer archivos, es más eficiente.
-
¿Cómo es “más eficiente” almacenar en búfer todo el archivo de datos en la memoria antes de enviarlo que transmitirlo?
– Rashad Rivera
6 oct a las 14:09
-
¿No entiendo tu punto? ¿A qué te refieres con “enviar”? En mi situación, solo necesito analizar el archivo pdf, no necesito responder
– levy9527
8 oct a las 8:03
obtiene el registro de la consola “El archivo se ha guardado” y el archivo se crea y solo el contenido es incorrecto?
– Roland Starke
27 de marzo de 2019 a las 10:19
donde estás llamando axios.get ? no esperará a que se escriba el archivo. mejor prometer el fs o usar fs-extra o usar métodos prometidos de fs. y usar como return fs.writeFile(…)
– AZ_
27 de marzo de 2019 a las 10:21
@RolandStarke sí, el archivo está guardado
– ar099968
27 de marzo de 2019 a las 10:27
He publicado un enfoque más limpio para resolver el problema usando canalizaciones de flujo de nodos a continuación. Está en el mismo concepto que propone la respuesta aceptada. stackoverflow.com/a/64925465/3476378
– Amán Saraf
20 de noviembre de 2020 a las 7:39