如何使用 StreamSaver.js 使用 Axios 的下载流?
How to consume the download stream from Axios using StreamSaver.js?
在我的服务器端,它是使用 Spring 启动框架构建的,它 returns 一个看起来像这样的流:
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. After some searches, I found a library called StreamSaver.js. This library works fine with 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 is not a function
那么,如何使用 Axios 从客户端消费流?或者也许有更好的解决方案?
因此,浏览器似乎没有实现流式传输功能(另请参阅 https://github.com/axios/axios/issues/479)。因此,您可能必须像示例中那样使用 fetch。
正如 , at the moment, Axios cannot consume a stream from the client-side (issue 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, and StreamSaver.js 2.0.3
在我的服务器端,它是使用 Spring 启动框架构建的,它 returns 一个看起来像这样的流:
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. After some searches, I found a library called StreamSaver.js. This library works fine with 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 is not a function
那么,如何使用 Axios 从客户端消费流?或者也许有更好的解决方案?
因此,浏览器似乎没有实现流式传输功能(另请参阅 https://github.com/axios/axios/issues/479)。因此,您可能必须像示例中那样使用 fetch。
正如
因此,解决方案是使用 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, and StreamSaver.js 2.0.3