How to consume the download stream from Axios using StreamSaver.js?

↘锁芯ラ 提交于 2020-01-25 00:20:34

问题


On my server-side, which is built using Spring Boot framework, it returns a stream which looks like this:

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);
}

It works fine for me. I can download the file using Postman. Now, I need to call this endpoint from the client-side using Axios. After some searches, I found a library called StreamSaver.js. This library works fine with fetch (view source to see the example code). However, I don't know how to use it with Axios.

Currently, my code looks like this (I use Vuejs):

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

const instance = axios.create({
    baseURL: 'http://141.5.98.232:8080',
    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);
});

I got an error saying that

response.data.pipe is not a function

So, how can I consume the stream from the client-side with Axios? Or maybe there is a better solution?


回答1:


So as it seems the streaming function is not implemented for the browser (see also https://github.com/axios/axios/issues/479). So you might have to use fetch like in the example.




回答2:


As pointed out by schnaidar, at the moment, Axios cannot consume a stream from the client-side (issue 479).

So, the solution is to use the fetch API instead. However, this is an experimental feature and not compatible with all browsers. According to my test, it works fine on Google Chrome but not with Firefox or Safari. To overcome this problem, I use another Javascript library called web-streams-polyfill.

Below is my code (only important parts included):

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);
});;

The idea is to check if window.WritableStream is available in the current browser or not. If not, assign the WritableStream from ponyfill directly to streamSaver.WritableStream property.

Tested on Google Chrome 78, Firefox 70, Safari 13; web-streams-polyfill 2.0.5, and StreamSaver.js 2.0.3



来源:https://stackoverflow.com/questions/58609130/how-to-consume-the-download-stream-from-axios-using-streamsaver-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!