如何使用 StreamSaver.js 从 Axios 消费下载流?

Posted

技术标签:

【中文标题】如何使用 StreamSaver.js 从 Axios 消费下载流?【英文标题】:How to consume the download stream from Axios using StreamSaver.js? 【发布时间】:2020-02-24 19:02:51 【问题描述】:

在我使用 Spring Boot 框架构建的服务器端,它返回如下所示的流:

public ResponseEntity<StreamingResponseBody> downloadFiles(@RequestBody DownloadRequest payload) 

    // Set proper header
    String contentDisposition = "attachment;filename=download.zip";

    // Build the response stream
    StreamingResponseBody stream = outputStream -> 
        archiveManagerService.downloadFiles(payload.getArchiveId(), payload.getFiles(), outputStream);
    ;

    return ResponseEntity.ok()
            .contentType(MediaType.parseMediaType("application/zip"))
            .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
            .body(stream);

它对我来说很好用。我可以使用 Postman 下载文件。现在,我需要使用Axios 从客户端调用此端点。经过一番搜索,我找到了一个名为StreamSaver.js 的库。这个库与fetch 一起工作得很好(查看源代码以查看示例代码)。但是,我不知道如何将它与 Axios 一起使用。

目前,我的代码如下所示(我使用 Vuejs):

import axios from 'axios';
import streamSaver from 'streamsaver';

const instance = axios.create(
    baseURL: '<my_base_url>',
    headers: 
        'Content-Type': 'application/json'
    
);

instance.post('/download', postData, 
    responseType: 'stream'
)
.then(response => 
    // What should I put here? These lines below don't work
    const fileStream = streamSaver.createWriteStream('download.zip');
    response.data.pipe(fileStream);
);

我说错了

response.data.pipe 不是函数

那么,如何使用 Axios 从客户端消费流?或者也许有更好的解决方案?

【问题讨论】:

【参考方案1】:

正如schnaidar 所指出的,目前,Axios 无法使用来自客户端 (issue 479) 的流。

因此,解决方案是改用fetch API。但是,这是一项实验性功能,并且不兼容所有浏览器。根据我的测试,它在 Google Chrome 上运行良好,但不适用于 Firefox 或 Safari。为了克服这个问题,我使用了另一个名为 web-streams-polyfilljavascript 库。

以下是我的代码(仅包括重要部分):

import  WritableStream  from 'web-streams-polyfill/ponyfill';
import streamSaver from 'streamsaver';

fetch(url, 
    method: 'POST',
    headers: 
        'Content-Type': 'application/json'
    ,
    body: JSON.stringify(data)
)
.then(response => 

    let contentDisposition = response.headers.get('Content-Disposition');
    let fileName = contentDisposition.substring(contentDisposition.lastIndexOf('=') + 1);

    // These code section is adapted from an example of the StreamSaver.js
    // https://jimmywarting.github.io/StreamSaver.js/examples/fetch.html

    // If the WritableStream is not available (Firefox, Safari), take it from the ponyfill
    if (!window.WritableStream) 
        streamSaver.WritableStream = WritableStream;
        window.WritableStream = WritableStream;
    

    const fileStream = streamSaver.createWriteStream(fileName);
    const readableStream = response.body;

    // More optimized
    if (readableStream.pipeTo) 
        return readableStream.pipeTo(fileStream);
    

    window.writer = fileStream.getWriter();

    const reader = response.body.getReader();
    const pump = () => reader.read()
        .then(res => res.done
            ? writer.close()
            : writer.write(res.value).then(pump));

    pump();
)
.catch(error => 
    console.log(error);
);;

这个想法是检查window.WritableStream 在当前浏览器中是否可用。如果没有,请将WritableStreamponyfill 直接分配给streamSaver.WritableStream 属性。

在 Google Chrome 78、Firefox 70、Safari 13 上测试; web-streams-polyfill 2.0.5 和 StreamSaver.js 2.0.3

【讨论】:

【参考方案2】:

因此,浏览器似乎没有实现流式传输功能(另请参阅https://github.com/axios/axios/issues/479)。因此,您可能必须像示例中那样使用 fetch。

【讨论】:

以上是关于如何使用 StreamSaver.js 从 Axios 消费下载流?的主要内容,如果未能解决你的问题,请参考以下文章

dma技术如何支持系统并发

AXI总线简介

axisarm接口时序

多个axi interconnect可以互联吗?

ZYNQ从入门到秃头11 DAC FIFO实验(AXI-stream FIFO IP核配置)

ZYNQ从入门到秃头10 DAC FIFO实验(AXI-stream FIFO IP核配置)