I'm working on a project with Vue.js and Typescript for front-end and Java Spring as backend.
My java controller retrieves a given report from the db and then copies it into the HTML response. I want the CSV to be downloaded by the browser therefore I added Content-disposition header in the response.
@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) {...}
}
I have 2 buttons: one simple hyperlink tag with href linking to download() , and a b-button (from bootstrap-vue) that once cliccked triggers download2() .
<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) {...}
}
Now, If I click on the first button "Download csv", the csv is correctly downloaded by the browser. The javascript console prints the following:
Resource interpreted as Document but transferred with MIME type text/csv
and there is nothing in the response body.
Instead, if I click the 2nd button "Download csv v2", the download does not start but I have the csv in the response body.
Here, the differences in the request headers between the two.
*Header* *Download csv* *Download csv v2*
Sec-Fetch-Dest document empty
Sec-Fetch-Mode navigate cors
Sec-Fetch-User ?1 -
Upgrade-Insecure-Requests 1 -
the other headers are the same. It is not possible to change these headers, even if I set them in the javascript method; they remain still the same. What's the problem? Thank you.
I found a solution by "mimicking" the behavior of a <a>
element:
This way, it works properly:
async download2() {
const configInit: RequestInit = {
method: 'GET'
};
try {
await fetch('http://localhost:8080/download', configInit)
.then(response => response.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = 'report.csv';
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
})
} catch (e) {...}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.