Eu tenho uma ação Struts2 no lado do servidor para download de arquivos.
<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>
No entanto, quando eu chamo a ação usando a jQuery:
$.post(
"/download.action",{
para1:value1,
para2:value2
....
},function(data){
console.info(data);
}
);
no Firebug eu vejo que os dados são recuperados com o Fluxo binário. Pergunto-me como abrir a janela de download de ficheiros com a qual o utilizador pode guardar o ficheiro localmente?
**2019 actualização dos browsers modernos***
Esta é a abordagem I'd agora recomendo com algumas advertências:
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!'));
**2012 Abordagem baseada em jQuery/iframe/Cookie original***
Bluish está completamente certo sobre isso, você pode't fazê-lo através do Ajax porque o JavaScript não pode salvar arquivos diretamente em um computador do usuário's (por questões de segurança). Infelizmente apontar a URL main window's para o seu download de arquivo significa que você tem pouco controle sobre qual é a experiência do usuário quando ocorre um download de arquivo.
Eu criei jQuery File Download que permite um "Ajax like" experiência com downloads de arquivos completos com OnSuccess e OnFailure callbacks para proporcionar uma melhor experiência ao usuário. Dê uma olhada no meu post no blog sobre o problema comum que o plugin resolve e algumas maneiras de usá-lo e também uma demo de jQuery File Download in action. Aqui está o fonte.
Aqui está uma demonstração de caso de uso simples usando o plugin fonte com promessas. A página demo inclui muitos outros, 'melhor UX' exemplos também.
$.fileDownload('some/file.pdf')
.done(function () { alert('File download a success!'); })
.fail(function () { alert('File download failed!'); });
Dependendo dos navegadores que você precisa suportar, você poderá usar https://github.com/eligrey/FileSaver.js/, que permite um controle mais explícito do que o método IFRAME jQuery File Download usa.
Ninguém postou isto @Pekka's solution... então I'irá postá-lo. Pode ajudar alguém.
Você não'não precisa fazer isso através do Ajax. Basta usar o
window.location="download.action?para1=value1...."
**1. Framework agnostic: ficheiro de download de servlet como anexo***.
<!-- with JS -->
<a href="javascript:window.location='downloadServlet?param1=value1'">
download
</a>
<!-- without JS -->
<a href="downloadServlet?param1=value1" >download</a>
2. Estrutura Struts2: Acção para descarregar ficheiro como anexo
<!-- with JS -->
<a href="javascript:window.location='downloadAction.action?param1=value1'">
download
</a>
<!-- without JS -->
<a href="downloadAction.action?param1=value1" >download</a>
Seria melhor utilizar <s:a>
tag apontando com OGNL para uma URL criada com <s:url>
tag:
<!-- 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>
Nos casos acima, você necessário* para escrever o cabeçalho Content-Disposition no response, especificando que o arquivo precisa ser baixado (attachment
) e não aberto pelo navegador (inline
). Você necessária* para especificar o Content Type também, e você pode querer adicionar o nome e comprimento do arquivo (para ajudar o navegador a desenhar uma barra de progresso realista).
Por exemplo, ao baixar um ZIP:
response.setContentType("application/zip");
response.addHeader("Content-Disposition",
"attachment; filename=\"name of my file.zip\"");
response.setHeader("Content-Length", myFile.length()); // or myByte[].length...
Com Struts2 (a menos que você esteja usando a Action como um Servlet, um hack para streaming direto, por exemplo), você não'não precisa escrever nada diretamente na resposta; simplesmente usando o Stream result type e configurando-o no struts.xml vai funcionar: EXEMPLO
<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. Framework agnostic (/ Struts2 framework): Servlet(/Action) abrindo arquivo dentro do navegador***
Se você quiser abrir o arquivo dentro do navegador, em vez de baixá-lo, a posição Content- deve ser definida como inline, mas o alvo pode't ser a localização da janela atual; você deve ter como alvo uma nova janela criada por javascript, um <iframe>
na página, ou uma nova janela criada on-the-fly com o "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>