代码之家  ›  专栏  ›  技术社区  ›  Abdennacer Lachiheb

Angular不从流下载文件(StreamingResponseBody)

  •  3
  • Abdennacer Lachiheb  · 技术社区  · 6 年前

    @RequestMapping(value = "/download", method = RequestMethod.GET)
    public StreamingResponseBody download(@PathVariable String path) throws IOException {
    
        final InputStream file =azureDataLakeStoreService.readFile(path);
        return (os) -> {
            readAndWrite(file , os);
        };
    }
    
    private void readAndWrite(final InputStream is, OutputStream os)
            throws IOException {
        byte[] data = new byte[2048];
        int read = 0;
        while ((read = is.read(data)) >= 0) {
            System.out.println("appending to file");
            os.write(data, 0, read);
        }
        os.flush();
    }
    

    curl -H "Authorization: Bearer <MyToken>" http://localhost:9001/rest/api/analyses/download --output test.zip
    

    但是,当我尝试使用angular下载文件时,它不起作用,即使请求成功,并且我可以在日志中看到多次显示的“追加到文件”文本,但浏览器上没有下载任何内容,以下是我的代码:

    this.http.get(url, { headers: headers, responseType: 'blob', observe: 'response' })
        .subscribe(response => {
            const contentDispositionHeader: string = response.headers.get('Content-Disposition');
            const parts: string[] = contentDispositionHeader.split(';');
            const filename = parts[1].split('=')[1];
            const blob = new Blob([response.body], {
                type: 'application/zip'
            });
            saveAs(blob, filename);
        });
    

    file-saver ,顺便说一句,当我试图下载一个字节[](无流)的文件时,上面的代码是有效的。

    code 当我使用angularJs时,有人能指出问题所在吗!谢谢

    更新 :

    我可以在Google chrome的“网络”选项卡上看到该文件正在下载,但我不知道该文件保存在哪里。

    enter image description here

    2 回复  |  直到 6 年前
        1
  •  1
  •   Svg_af    6 年前

    我尝试使用您的后端代码,但在angular中,我使用了以下代码:

    window.location.href = "http://localhost:9001/rest/api/analyses/download";
    

    并成功开始下载。

        2
  •  1
  •   Abdennacer Lachiheb    6 年前

    似乎我错过了带有标题的arround,在保存时,这是最终版本,它可能会帮助其他人:

    将这些配置添加到 :

    @Configuration
    public static class WebConfig extends WebMvcConfigurerAdapter {
    
        @Override
        public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
            configurer.setDefaultTimeout(-1);
            configurer.setTaskExecutor(asyncTaskExecutor());
        }
    
        @Bean
        public AsyncTaskExecutor asyncTaskExecutor() {
            return new SimpleAsyncTaskExecutor("async");
        }
    
    }
    

    这是给你的控制器的:

    @RequestMapping(value = "{analyseId}/download", method = RequestMethod.GET, produces = "application/zip")
    public ResponseEntity<StreamingResponseBody> download(@PathVariable Long analyseId) throws IOException {
        try {
            Analyse analyse = analyseService.getAnalyse(analyseId);
    
            final InputStream file =azureDataLakeStoreService.readFile(analyse.getZippedFilePath());
            Long fileLength = azureDataLakeStoreService.getContentSummary(analyse.getZippedFilePath()).length;
            StreamingResponseBody stream = outputStream ->
                    readAndWrite(file , outputStream);
    
            String zipFileName = FilenameUtils.getName(analyse.getZippedFilePath());
            return ResponseEntity.ok()
                    .header(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION)
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + zipFileName)
                    .contentLength(fileLength)
                    .contentType(MediaType.parseMediaType("application/zip"))
                    .body(stream);
        } catch (Exception e) {
            e.printStackTrace();
            return ExceptionMapper.toResponse(e);
        }
    }
    
    private void readAndWrite(final InputStream is, OutputStream os)
            throws IOException {
        byte[] data = new byte[2048];
        int read = 0;
        while ((read = is.read(data)) >= 0) {
            os.write(data, 0, read);
        }
        os.flush();
    }
    

    download(id) {
        let url = URL + '/analyses/' + id + '/download';
        const headers = new HttpHeaders().set('Accept', 'application/zip');
        const req = new HttpRequest('GET', url, {
            headers: headers,
            responseType: 'blob',
            observe: 'response',
            reportProgress: true,
        });
        const dialogRef = this.dialog.open(DownloadInProgressDialogComponent);
        this.http.request(req).subscribe(event => {
            if (event.type === HttpEventType.DownloadProgress) {
                dialogRef.componentInstance.progress = Math.round(100 * event.loaded / event.total) // download percentage
            } else if (event instanceof HttpResponse) {
                dialogRef.componentInstance.progress = 100;
                this.saveToFileSystem(event, 'application/zip');
                dialogRef.close();
            }
        });
    }
    
    private saveToFileSystem(response, type) {
        const contentDispositionHeader: string = response.headers.get('Content-Disposition');
        const parts: string[] = contentDispositionHeader.split(';');
        const filename = parts[1].split('=')[1];
        const blob = new Blob([response.body], {
            type: type
        });
        saveAs(blob, filename);
    }