如何使用 StreamSaver.js 从 Axios 使用下载流? [英] How to consume the download stream from Axios using StreamSaver.js?

查看:134
本文介绍了如何使用 StreamSaver.js 从 Axios 使用下载流?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

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.

目前,我的代码是这样的(我使用 Vuejs):

Currently, my code looks like this (I use 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 不是函数

response.data.pipe is not a function

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

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

推荐答案

正如 schnaidar 所指出的,目前, Axios 不能从客户端消费流(issue 479).

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

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

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

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

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.

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

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

这篇关于如何使用 StreamSaver.js 从 Axios 使用下载流?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆