Estoy usando axios para peticiones http básicas como GET y POST, y funciona bien. Ahora necesito poder descargar también archivos Excel. ¿Es esto posible con axios? Si es así ¿alguien tiene algún código de ejemplo? Si no, ¿qué otra cosa puedo usar en una aplicación React para hacer lo mismo?
Cuando la respuesta viene con un archivo descargable, las cabeceras de respuesta serán algo así como
Content-Disposition: "attachment;filename=report.xls"
Content-Type: "application/octet-stream" // or Content-type: "application/vnd.ms-excel"
Lo que puede hacer es crear un componente separado, que contendrá un iframe oculto.
import * as React from 'react';
var MyIframe = React.createClass({
render: function() {
return (
<div style={{display: 'none'}}>
<iframe src={this.props.iframeSrc} />
</div>
);
}
});
Ahora, usted puede pasar la url del archivo descargable como prop a este componente, así que cuando este componente recibirá prop, se re-renderá y el archivo será descargado.
Edición: También puedes usar el módulo js-file-download. Enlace al repo de Github
const FileDownload = require('js-file-download');
Axios.get(`http://localhost/downloadFile`)
.then((response) => {
FileDownload(response.data, 'report.csv');
});
Espero que esto ayude :)
En realidad, esto es aún más complejo cuando quieres descargar archivos usando Axios y algún medio de seguridad. Para evitar que alguien más pierda demasiado tiempo en averiguar esto, déjame guiarte a través de esto.
Necesitas hacer 3 cosas:
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
Estos pasos son en su mayoría factibles - pero se complican considerablemente por la relación del navegador con CORS. Un paso a la vez:
Cuando se emplea la seguridad de transporte, el JavaScript que se ejecuta dentro de un navegador puede [por diseño] acceder sólo a 6 de las cabeceras HTTP realmente enviadas por el servidor HTTP. Si queremos que el servidor sugiera un nombre de archivo para la descarga, debemos informar al navegador de que está "OK" para que JavaScript tenga acceso a otras cabeceras donde se transportaría el nombre de archivo sugerido.
Supongamos - por el bien de la discusión - que queremos que el servidor transmita el nombre de archivo sugerido dentro de una cabecera HTTP llamada X-Suggested-Filename. El servidor HTTP le dice al navegador que está OK para exponer esta cabecera personalizada recibida al JavaScript/Axios con la siguiente cabecera:
Access-Control-Expose-Headers: X-Suggested-Filename
La forma exacta de configurar el servidor HTTP para establecer este encabezado varía de un producto a otro.
Consulte https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers para obtener una explicación completa y una descripción detallada de estas cabeceras estándar.
Su implementación del servicio del lado del servidor debe ahora realizar 2 cosas:
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
Esto se hace de diferentes maneras dependiendo de la pila de tecnología elegida. Voy a esbozar un ejemplo utilizando el estándar JavaEE 7 que debe emitir un informe de Excel:
@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();
}
El servicio ahora emite el documento binario (un informe de Excel, en este caso), establece el tipo de contenido correcto - y también envía una cabecera HTTP personalizada que contiene el nombre de archivo sugerido para usar al guardar el documento.
Hay algunas trampas aquí, así que vamos a asegurarnos de que todos los detalles están correctamente configurados:
El esqueleto de la implementación de Axios sería entonces algo parecido a
// 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);
});
Mi respuesta es un total hack- Acabo de crear un enlace que se parece a un botón y añadir la URL a eso.
<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> Excel
</a>
Estoy usando el excelente VueJs de ahí las anotaciones extrañas, sin embargo, esta solución es agnóstica de marco. La idea funcionaría para cualquier diseño basado en HTML.