【发布时间】:2020-03-10 10:48:53
【问题描述】:
我正在开发一个项目,其中 Vue.js 和 Typescript 作为前端,Java Spring 作为后端。
我的 java 控制器从数据库中检索给定的报告,然后将其复制到 HTML 响应中。 我希望浏览器下载 CSV,因此我在响应中添加了 Content-disposition 标头。
@GetMapping('/download')
public void downloadCSV(HttpServletRequest response){
Report r = reportService.findById(85);
response.addHeader("Content-Disposition", "attachment; filename=myCSV.csv");
response.setContentType("text/csv");
try {
InputStream stream = new ByteArrayInputStream(r.getDocument());
IOUtils.copy(stream, response.getOutputStream());
response.flushBuffer();
} catch(Exception e) {...}
}
我有 2 个按钮:一个带有 href 链接到 download() 的简单超链接标签,以及一个一旦点击就会触发 download2() 的 b 按钮(来自 bootstrap-vue) em>。
<a :href="download" role="button"> Download CSV </a>
<b-button @click="event => download2()">
Download CSV v2
</b-button>
get download(): string {
return 'http://localhost:8080/download';
}
async download2() {
const rHeaders = new Headers();
rHeaders.append('Accept', 'text/csv');
const configInit = RequestInit = {
method: 'GET',
headers: rHeaders
};
try {
const res = await fetch('http://localhost:8080/download', configInit);
return res.text();
} catch (e) {...}
}
现在,如果我点击第一个按钮“下载 csv”,浏览器会正确下载 csv。 javascript 控制台打印以下内容:
Resource interpreted as Document but transferred with MIME type text/csv
响应正文中没有任何内容。
相反,如果我点击第二个按钮“下载 csv v2”,下载不会开始,但响应正文中有 csv。
这里是两者请求头的区别。
*Header* *Download csv* *Download csv v2*
Sec-Fetch-Dest document empty
Sec-Fetch-Mode navigate cors
Sec-Fetch-User ?1 -
Upgrade-Insecure-Requests 1 -
其他标题相同。无法更改这些标头,即使我在 javascript 方法中设置它们;它们保持不变。 有什么问题? 谢谢。
【问题讨论】:
-
只是一个想法:是什么让您认为响应不同?浏览器的行为不同,但毕竟,单击 HTML 超链接与启动异步请求(AJAX 风格)完全是不同的野兽。您是否真的观察到(例如,从浏览器的网络检查器)响应不同?
-
@GPI 你说得对,我说得不好。响应基本相同(所有标题都相同),除了一个(第一个)是“文档”类型,另一个是“获取”类型(来自网络检查器)。浏览器的行为发生变化。我想弄清楚为什么,实际上它们都是 GET 请求。
-
感谢您的澄清。因此,我建议您完全改写您的问题,
-
因为您的问题似乎与浏览器相关而不是后端相关。问题不是 spring / java 部分,而是如何从浏览器获取触发浏览器下载
-
感谢@GPI 的建议,我会改写。
标签: javascript java spring csv fetch-api