Как использовать поток загрузки из Axios с помощью StreamSaver.js? - PullRequest
1 голос
/ 29 октября 2019

На моей стороне сервера, которая построена с использованием Spring Boot Framework, он возвращает поток, который выглядит следующим образом:

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

Он прекрасно работает для меня. Я могу скачать файл с помощью Почтальона. Теперь мне нужно вызвать эту конечную точку со стороны клиента , используя Axios . После некоторых поисков я нашел библиотеку с именем StreamSaver.js . Эта библиотека прекрасно работает с fetch (просмотрите исходный код, чтобы увидеть пример кода). Тем не менее, я не знаю, как использовать его с Axios.

В настоящее время мой код выглядит следующим образом (я использую 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);
});

Я получил сообщение о том, что

response.data.pipe не является функцией

Итак, как я могу использовать поток со стороны клиента с Axios? Или, может быть, есть лучшее решение?

Ответы [ 2 ]

1 голос
/ 01 ноября 2019

Так что, как кажется, функция потоковой передачи не реализована для браузера (см. Также https://github.com/axios/axios/issues/479). Так что вам, возможно, придется использовать fetch, как в примере.

0 голосов
/ 04 ноября 2019

Как указывает schnaidar , в настоящий момент Axios не может потреблять поток со стороны клиента ( выпуск 479 ).

Итак, решениевместо этого использовать fetch API. Однако это экспериментальная функция и не совместима со всеми браузерами . Согласно моему тесту, он отлично работает на Google Chrome, но не на Firefox или Safari. Чтобы преодолеть эту проблему, я использую другую библиотеку Javascript под названием web-streams-polyfill.

Ниже приведен мой код (включены только важные части):

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 в текущем браузере или нет. Если нет, присвойте WritableStream непосредственно из ponyfill свойству streamSaver.WritableStream.

Протестировано в Google Chrome 78, Firefox 70, Safari 13; web-streams-polyfill 2.0.5 и StreamSaver.js 2.0.3

...