Jeg har en Struts2-handling på serversiden for nedlasting av filer.
<action name="download" class="com.xxx.DownAction">
<result name="success" type="stream">
<param name="contentType">text/plain</param>
<param name="inputName">imageStream</param>
<param name="contentDisposition">attachment;filename={fileName}</param>
<param name="bufferSize">1024</param>
</result>
</action>
Men når jeg kaller handlingen ved hjelp av jQuery:
$.post(
"/download.action",{
para1:value1,
para2:value2
....
},function(data){
console.info(data);
}
);
i Firebug ser jeg at dataene hentes med Binary stream. Jeg lurer på hvordan jeg åpner filnedlastingsvinduet som brukeren kan lagre filen lokalt med?
2019 oppdatering av moderne nettlesere
Dette er tilnærmingen jeg nå vil anbefale, med noen få forbehold:
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(resp => resp.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
// the filename you want
a.download = 'todo-1.json';
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
alert('your file has downloaded!'); // or you know, something with better UX...
})
.catch(() => alert('oh no!'));
Original jQuery/iframe/Cookie-basert tilnærming fra 2012.
Bluish har helt rett i dette, du kan ikke gjøre det via Ajax fordi JavaScript ikke kan lagre filer direkte på en brukers datamaskin (av sikkerhetshensyn). Dessverre betyr det å peke hovedvinduets nettadresse mot filnedlastingen at du har liten kontroll over brukeropplevelsen når en fil lastes ned.
Jeg opprettet jQuery File Download som gir en "Ajax-lignende" opplevelse med filnedlastinger komplett med OnSuccess og OnFailure callbacks for å gi en bedre brukeropplevelse. Ta en titt på mitt blogginnlegg om det vanlige problemet som pluginet løser og noen måter å bruke det på, og også en demo av jQuery File Download i aksjon. Her er kilden
Her er en enkel brukstilfelle demo ved hjelp av plugin kilde med løfter. Demosiden]7 inneholder også mange andre og bedre UX-eksempler.
$.fileDownload('some/file.pdf')
.done(function () { alert('File download a success!'); })
.fail(function () { alert('File download failed!'); });
Avhengig av hvilke nettlesere du trenger å støtte, kan du kanskje bruke https://github.com/eligrey/FileSaver.js/ som gir mer eksplisitt kontroll enn IFRAME-metoden jQuery File Download bruker.
Ingen har lagt ut denne @Pekkas løsning... så jeg legger den ut. Det kan hjelpe noen.
Du trenger ikke å gjøre dette gjennom Ajax. Bare bruk
window.location="download.action?para1=value1...."
1. Framework agnostic: Servlet laster ned fil som vedlegg.
<!-- with JS -->
<a href="javascript:window.location='downloadServlet?param1=value1'">
download
</a>
<!-- without JS -->
<a href="downloadServlet?param1=value1" >download</a>
2. Struts2-rammeverk: Handling nedlasting av fil som vedlegg
<!-- with JS -->
<a href="javascript:window.location='downloadAction.action?param1=value1'">
download
</a>
<!-- without JS -->
<a href="downloadAction.action?param1=value1" >download</a>
Det ville være bedre å bruke <s:a>
-taggen som peker med OGNL til en URL opprettet med <s:url>
-taggen:
<!-- without JS, with Struts tags: THE RIGHT WAY -->
<s:url action="downloadAction.action" var="url">
<s:param name="param1">value1</s:param>
</s:ulr>
<s:a href="%{url}" >download</s:a>
I de ovennevnte tilfellene må du skrive Content-Disposition-headeren til response, og angi at filen må lastes ned (attachment
) og ikke åpnes av nettleseren (inline
). Du må også angi Content Type, og det kan være lurt å legge til filnavn og lengde (for å hjelpe nettleseren med å tegne en realistisk fremdriftslinje).
For eksempel når du laster ned en ZIP-fil:
response.setContentType("application/zip");
response.addHeader("Content-Disposition",
"attachment; filename=\"name of my file.zip\"");
response.setHeader("Content-Length", myFile.length()); // or myByte[].length...
Med Struts2 (med mindre du bruker Action as a Servlet, et hack for direkte streaming, for eksempel), trenger du ikke å skrive noe direkte til svaret; det er bare å bruke Stream result type og konfigurere det i struts.xml: EXAMPLE
<result name="success" type="stream">
<param name="contentType">application/zip</param>
<param name="contentDisposition">attachment;filename="${fileName}"</param>
<param name="contentLength">${fileLength}</param>
</result>
3. Rammeverk agnostisk (/ Struts2-rammeverk): Servlet(/Action) som åpner filen i nettleseren.
Hvis du vil åpne filen i nettleseren i stedet for å laste den ned, må Content-disposition settes til inline, men målet kan ikke være det gjeldende vinduet; du må målrette mot et nytt vindu opprettet av javascript, en <iframe>
på siden, eller et nytt vindu opprettet på farten med "discussed" target="_blank":
<!-- From a parent page into an IFrame without javascript -->
<a href="downloadServlet?param1=value1" target="iFrameName">
download
</a>
<!-- In a new window without javascript -->
<a href="downloadServlet?param1=value1" target="_blank">
download
</a>
<!-- In a new window with javascript -->
<a href="javascript:window.open('downloadServlet?param1=value1');" >
download
</a>