当使用带有Express API的React客户端时,React客户端如何下载Express API发送的文件?
问题:
Express服务器
// Route handler for /api/files/testfile
const getFile = async (req, res, next) => {
// File
const fileName = 'file.csv';
const filePath = path.join(__dirname, '/../../public/', fileName);
// File options
const options = {
headers: {
'x-timestamp': Date.now(),
'x-sent': true,
'content-disposition': "attachment; filename=" + fileName, // gets ignored
'content-type': "text/csv"
}
}
try {
res.download(
filePath,
fileName,
options
);
console.log("File sent successfully!");
}
catch (error) {
console.error("File could not be sent!");
next(error);
}
});
React client
// When the user clicks the "Download as CSV" button
handleDownloadFile = () => {
axios
.get(
`/api/files/testfile`, {
responseType: 'blob',
headers: {
'Content-Type': 'text/csv',
}
}
)
.then(response => {
console.log(response.headers); // does not include content-disposition
console.log("File downloading successfully!");
})
.catch( (error) => {
console.error("File could not be downloaded:", error);
});
}
我读到这可能与content-disposition
标头有关。我尝试设置(请参见上面的代码),但标头未发送到客户端。
不良的“解决方案”:
在React应用程序中:创建一个新的a
元素,设置其href
属性并通过JavaScript触发一个click
。我正在寻找不需要此JS hack的解决方案。
在React应用程序中:将a
与target="_blank"
一起使用,而不是Axios。但是,这不适合我,因为它将绕过我的axios配置设置(API URL,身份验证令牌等)
似乎您必须根据此示例告诉axios文件直接在哪里:
axios({
url: 'http://localhost:5000/static/example.pdf',
method: 'GET',
responseType: 'blob', // important
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf');
document.body.appendChild(link);
link.click();
});
我假设您可以简单地更改api上的响应以使用文件的新Blob返回Blob。但是似乎需要的主要部分是axios get呼叫上的.then响应。这样,您仍然可以通过jwt验证用户的状态并适当保护文件。
[不幸的是,没有可靠的,跨平台的方法可以触发正常网页的浏览器下载行为,这在这里很合适。由于您不能在普通的DOM锚标记上使用带有内容处置,重定向或数据URI的纯URL,因此,在没有创建隐藏的a
并单击它的情况下,我看不到另一种导致下载的方法。但是,这似乎很好用(并且确实是流行的实用程序,例如filesaver.js使用的机制)
在React中构建一个简单的DownloadButton
组件来执行此操作非常简单。 Here's a working codepen模拟Axios响应,否则将开始结束,除非您要进行任何重构。我出于自身的理智/明朗起见,正在使用钩子和async/await
,但两者均非严格必要。它确实在锚标记上使用download
attribute,在现代浏览器中都具有良好的支持。
download