Estoy usando vuejs 2 + axios. Necesito enviar una solicitud get, pasar algunos params al servidor, y obtener un PDF como respuesta. El servidor utiliza Laravel.
Así
axios.get(`order-results/${id}/export-pdf`, { params: { ... }})
realiza la solicitud correctamente pero no inicia la descarga forzada, aunque el servidor devuelve cabeceras correctas.
Creo que esta es una situación típica cuando se necesita, digamos, formar un informe PDF y pasar algunos filtros al servidor. Entonces, ¿cómo se podría lograr?
Actualización
Así que en realidad he encontrado una solución. Sin embargo, el mismo enfoque no funcionó con axios, no sé por qué, es por eso que he utilizado raw XHR object. Así que la solución es crear un objeto blob y usar la función createUrlObject
. Ejemplo de ejemplo:
let xhr = new XMLHttpRequest()
xhr.open('POST', Vue.config.baseUrl + `order-results/${id}/export-pdf`, true)
xhr.setRequestHeader("Authorization", 'Bearer ' + this.token())
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
xhr.responseType = 'arraybuffer'
xhr.onload = function(e) {
if (this.status === 200) {
let blob = new Blob([this.response], { type:"application/pdf" })
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'Results.pdf'
link.click()
}
}
Importante: debes tener array buffer como tipo de respuesta
Sin embargo, el mismo código escrito en axios devuelve PDF que está vacío:
axios.post(`order-results/${id}/export-pdf`, {
data,
responseType: 'arraybuffer'
}).then((response) => {
console.log(response)
let blob = new Blob([response.data], { type: 'application/pdf' } ),
url = window.URL.createObjectURL(blob)
window.open(url); // Mostly the same, I was just experimenting with different approaches, tried link.click, iframe and other solutions
})
Obtiene un PDF vacío porque no se pasan datos al servidor. Usted puede tratar de pasar los datos utilizando el objeto de datos de la siguiente manera
begin snippet: js hide: false console: true babel: false -->
axios
.post(`order-results/${id}/export-pdf`, {
data: {
firstName: 'Fred'
},
responseType: 'arraybuffer'
})
.then(response => {
console.log(response)
let blob = new Blob([response.data], { type: 'application/pdf' }),
url = window.URL.createObjectURL(blob)
window.open(url) // Mostly the same, I was just experimenting with different approaches, tried link.click, iframe and other solutions
})
Por cierto tengo que agradecerte mucho por mostrarme la pista para poder descargar pdf desde response. Gracias :)
var dates = {
fromDate: 20/5/2017,
toDate: 25/5/2017
}
La forma en que he utilizado es,
begin snippet: js hide: false console: true babel: false -->
axios({
method: 'post',
url: '/reports/interval-dates',
responseType: 'arraybuffer',
data: dates
}).then(function(response) {
let blob = new Blob([response.data], { type: 'application/pdf' })
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'Report.pdf'
link.click()
})
No creo que sea posible hacer esto en axios o incluso en AJAX. El archivo se mantendrá en memoria, es decir, no se puede guardar en disco. Esto se debe a que JavaScript no puede interactuar con el disco. Eso sería un grave problema de seguridad y está bloqueado en los principales navegadores.
Puede construir su URL en front-end y descargarlo de la siguiente manera:
var url = 'http://example.com/order-results/' + id + '/export-pdf?' + '..params..'
window.open(url, '_blank');
Espero que te sirva de ayuda.