如何使用StreamSaver.js消耗来自Axios的下载流? [英] How to consume the download stream from Axios using StreamSaver.js?
问题描述
在我的使用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);
}
对我来说很好.我可以使用邮递员下载文件.现在,我需要使用 Axios 从客户端将此端点称为 .经过一些搜索,我发现了一个名为 StreamSaver.js 的库.该库可以与获取正常工作(查看源代码以查看示例代码) ).但是,我不知道如何在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从客户端使用流?还是有更好的解决方案?
目前 schnaidar 指出,Axios无法从客户端使用流(问题479 ).>
因此,解决方案是改用fetch
API.但是,这是一项实验性功能,与所有浏览器都不兼容.根据我的测试,它可以在Google Chrome上正常运行,但不能在Firefox或Safari上运行.为了克服这个问题,我使用了另一个名为web-streams-polyfill
的Javascript库.
下面是我的代码(仅包括重要部分):
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
属性.
在Google Chrome 78,Firefox 70,Safari 13上进行了测试; web-streams-polyfill 2.0.5 ,以及 StreamSaver.js 2.0.3
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?
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
这篇关于如何使用StreamSaver.js消耗来自Axios的下载流?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!