在 React App 中使用 Axios 将响应数据下载为流
Download Response Data as Stream w/ Axios in React App
问题
我需要通过将结果流式传输到 CSV 文件来从端点下载查询结果。这是为了支持一次通过浏览器发送大量的结果集。
有没有办法在 React 应用程序的上下文中使用 Axios 来完成此操作?
看过fetch(),知道它有以下特点:
- returns 可读流
- IE11 不支持
- 不允许拦截请求
- 响应的状态与请求本身有关,与 HTTP 状态无关
- 这意味着收到错误的唯一方法是让流过早结束出现问题
- 这对我来说绝对行不通,因为我有与用户权限相关的自定义错误处理
除了ReadableStream
响应类型外,其余列出的特征都是不允许的。我将需要支持 IE11 并允许拦截请求/读取 HTTP 状态以确定如何处理流量。
示例fetch
:
// The promise returned by `fetch` rejects if the fetch was unable to make HTTP-request
// e.g. network problems, or there’s no such site.
// Abnormal HTTP-statuses, such as 404 or 500 do not cause an error.
const results = await fetch(`${URL}/data`, {
method: 'post', // HTTP POST to send query to server
headers: {
Accept: 'application/json, text/plain, */*', // indicates which files we are able to understand
'Content-Type': 'application/json', // indicates what the server actually sent
},
body: JSON.stringify(query), // server is expecting JSON
credentials: 'include', // sends the JSESSIONID cookie with the address
}).then(res => res.json()) // turn the ReadableStream response back into JSON
.then((res) => {
if (res.ok) {
// boolean, true if the HTTP status code is 200-299.
console.log('response.ok!');
} else if (res.status === 401) {
throw Error(`You are not authenticated. Please login.`);
} else if (res.status === 403) {
throw Error(`You are not authorized to access this data.`);
} else {
throw Error(`Request rejected with status ${res.status}`);
}
})
.catch((error) => {
// catches error case and if fetch itself rejects
error.response = {
status: 0,
statusText:
'Cannot connect. Please make sure you are connected to internet.',
};
throw error;
});
console.log(results);
axios
示例(非流式传输)
Axios 实例
import ...
const Api = axios.create({
baseURL: `${URL}`,
withCredentials: true,
});
// attach interceptors to requests and responses
// these are defined elsewhere and imported
Api.interceptors.request.use((request) => requestHandler(request));
Api.interceptors.response.use((response) => successHandler(response), (error) => errorHandler(error));
export default Api;
axios 请求
const query = {"selections":{"TABLE_A":["COLUMN1"]},"filters":[{"predicates":[]}],"joins":[],"sorts":[],"limit":100,"offset":0}
const response = await Api.post('/data', query);
// further transformations to response to get formatted csv results required
关于axios的问题
- 是否可以在 Axios 中使用与
fetch
相同的 ReadableStream
?
- Axios 中的流是否只有在假设 Node 在仅服务器端设置中支持时才可能?
- 像 this 这样的网站似乎说使用
responseType: 'stream'
不能在浏览器中完成,只有 Node.js 使用 fs
- 是否可以将
fetch
或其他东西与 Axios 结合使用?
目前不支持从浏览器流式传输响应:
https://github.com/axios/axios/issues/479
由于我们在浏览器中处理 XMLHttpRequests
,Axios 仅限于 whatwg
设置的规范。 :
具体来说,这些是唯一受支持的类型:
enum XMLHttpRequestResponseType {
"",
"arraybuffer",
"blob",
"document",
"json",
"text"
};
stream
在 axios 中设置 responseType
时被接受,但这是误导。由于我们使用的是依赖 XMLHttpRequests 的浏览器,因此适配器将隐式设置为 xhr.js
。 HttpRequest 是在服务器端发出的,将允许 axios 使用 http.js
适配器。那么您可以使用 stream
作为带有 Node.js 的 ResponseType。
使用 fetch
API 似乎是唯一将 ReadableStream
作为响应主体类型的解决方案。
如果你只是需要下载一个文件,在responseType
选项中使用blob
绝对可以。
axios.post(url, param,
{ header: {...}, responseType: 'blob' }
)
.then(res => {
const link = document.createElement('a');
link.href = URL.createObjectURL(res);
link.click();
})
问题
我需要通过将结果流式传输到 CSV 文件来从端点下载查询结果。这是为了支持一次通过浏览器发送大量的结果集。
有没有办法在 React 应用程序的上下文中使用 Axios 来完成此操作?
看过fetch(),知道它有以下特点:
- returns 可读流
- IE11 不支持
- 不允许拦截请求
- 响应的状态与请求本身有关,与 HTTP 状态无关
- 这意味着收到错误的唯一方法是让流过早结束出现问题
- 这对我来说绝对行不通,因为我有与用户权限相关的自定义错误处理
除了ReadableStream
响应类型外,其余列出的特征都是不允许的。我将需要支持 IE11 并允许拦截请求/读取 HTTP 状态以确定如何处理流量。
示例fetch
:
// The promise returned by `fetch` rejects if the fetch was unable to make HTTP-request
// e.g. network problems, or there’s no such site.
// Abnormal HTTP-statuses, such as 404 or 500 do not cause an error.
const results = await fetch(`${URL}/data`, {
method: 'post', // HTTP POST to send query to server
headers: {
Accept: 'application/json, text/plain, */*', // indicates which files we are able to understand
'Content-Type': 'application/json', // indicates what the server actually sent
},
body: JSON.stringify(query), // server is expecting JSON
credentials: 'include', // sends the JSESSIONID cookie with the address
}).then(res => res.json()) // turn the ReadableStream response back into JSON
.then((res) => {
if (res.ok) {
// boolean, true if the HTTP status code is 200-299.
console.log('response.ok!');
} else if (res.status === 401) {
throw Error(`You are not authenticated. Please login.`);
} else if (res.status === 403) {
throw Error(`You are not authorized to access this data.`);
} else {
throw Error(`Request rejected with status ${res.status}`);
}
})
.catch((error) => {
// catches error case and if fetch itself rejects
error.response = {
status: 0,
statusText:
'Cannot connect. Please make sure you are connected to internet.',
};
throw error;
});
console.log(results);
axios
示例(非流式传输)
Axios 实例
import ...
const Api = axios.create({
baseURL: `${URL}`,
withCredentials: true,
});
// attach interceptors to requests and responses
// these are defined elsewhere and imported
Api.interceptors.request.use((request) => requestHandler(request));
Api.interceptors.response.use((response) => successHandler(response), (error) => errorHandler(error));
export default Api;
axios 请求
const query = {"selections":{"TABLE_A":["COLUMN1"]},"filters":[{"predicates":[]}],"joins":[],"sorts":[],"limit":100,"offset":0}
const response = await Api.post('/data', query);
// further transformations to response to get formatted csv results required
关于axios的问题
- 是否可以在 Axios 中使用与
fetch
相同的ReadableStream
? - Axios 中的流是否只有在假设 Node 在仅服务器端设置中支持时才可能?
- 像 this 这样的网站似乎说使用
responseType: 'stream'
不能在浏览器中完成,只有 Node.js 使用fs
- 像 this 这样的网站似乎说使用
- 是否可以将
fetch
或其他东西与 Axios 结合使用?
目前不支持从浏览器流式传输响应:
https://github.com/axios/axios/issues/479
由于我们在浏览器中处理 XMLHttpRequests
,Axios 仅限于 whatwg
设置的规范。 :
具体来说,这些是唯一受支持的类型:
enum XMLHttpRequestResponseType {
"",
"arraybuffer",
"blob",
"document",
"json",
"text"
};
stream
在 axios 中设置 responseType
时被接受,但这是误导。由于我们使用的是依赖 XMLHttpRequests 的浏览器,因此适配器将隐式设置为 xhr.js
。 HttpRequest 是在服务器端发出的,将允许 axios 使用 http.js
适配器。那么您可以使用 stream
作为带有 Node.js 的 ResponseType。
使用 fetch
API 似乎是唯一将 ReadableStream
作为响应主体类型的解决方案。
如果你只是需要下载一个文件,在responseType
选项中使用blob
绝对可以。
axios.post(url, param,
{ header: {...}, responseType: 'blob' }
)
.then(res => {
const link = document.createElement('a');
link.href = URL.createObjectURL(res);
link.click();
})