Entonces, cuando solicito mi servicio web para descargar un archivo zip, descarga el contenido del archivo en secreto y, de repente, el archivo aparece en la barra de tareas de descarga pero ya se descargó por completo (100%).
Usando el siguiente método angular:
const endpoint = "http://localhost:8080/download/zip" this.http.get<Blop>(endpoint, {headers: httpHeaders, responseType: 'blob', reportProgress: true })Así que así es como me estoy suscribiendo:
this.http.get<Blop>(endpoint, {headers: httpHeaders, responseType: 'blob', reportProgress: true }).subscribe({ next: data => { console.log('blocking or not'); const blob = new Blob([data as any], { type: 'application/zip' }); window.location.href = URL.createObjectURL(blob); } }) Así que noté que mi console.log(...) no se llama hasta el final de la descarga, así que supongo que la interfaz de usuario del navegador no puede detectar la descarga hasta que llega a window.location.href .
¿Cómo forzar que la descarga se muestre en la barra de tareas de descarga antes del final de la transferencia y ver el progreso de la descarga en el navegador? No pude encontrar nada relacionado con async blop o algo así.
PD: mi backend sirve un flujo de datos, por lo que el backend no es el problema. Al llamar a mi api directamente a través del navegador, podemos ver el progreso de la descarga en la barra de tareas de descarga. Aún así, si están interesados, este es el fragmento (spring-boot)
@GetMapping("/download/zip") fun download(response: HttpServletResponse): StreamingResponseBody { val file = downloads.download("launcher") response.contentType = "application/zip" response.setHeader( "Content-Disposition", "attachment;filename=sample.zip" ) response.setContentLengthLong(file.length()) return StreamingResponseBody { outputStream: OutputStream -> var bytesRead: Int val buffer = ByteArray(2048) val inputStream: InputStream = file.inputStream() while (inputStream.read(buffer).also { bytesRead = it } != -1) { outputStream.write(buffer, 0, bytesRead) } } }Para descargar tienes 2 formas:
Parece que no hay posibilidad de mezclar estos 2 enfoques y, en general, diría que el primero es más moderno y preferible para archivos pequeños; sin embargo, si no está satisfecho con él, intente con el segundo ( https://stackoverflow.com/a/ 49917066/4019404 ):
function download(url) { const a = document.createElement('a') a.href = url a.download = url.split('/').pop() document.body.appendChild(a) a.click() document.body.removeChild(a) }Suponiendo que está utilizando HttpClient de Angular, algo como esto debería funcionar:
const endpoint = "http://localhost:8080/download/zip" const req = new HttpRequest('GET', endpoint, { reportProgress: true, }) this.Http.request(req).subscribe(event => { if (event.type === HttpEventType.DownloadProgress) { const percentDone = Math.round(100 * event.loaded / (event.total || 0)) console.log(percentDone); } else if (event instanceof HttpResponse) { const blob = new Blob([event.body as any], { type: 'application/zip' }); window.location.href = URL.createObjectURL(blob); } })Simplemente puede usar este paquete
npm i ngx-filesavery
constructor(private _http: Http, private _FileSaverService: FileSaverService) { } onSave() { this._http.get('yourfile.png', { responseType: ResponseContentType.Blob // This must be a Blob type }).subscribe(res => { this._FileSaverService.save((<any>res)._body, fileName); }); }complete el documento aquí ngx file saver y también file saver.js