56 Stimmen

Wie erzwinge ich, dass der Browser die Datei herunterlädt?

Alles funktioniert gut, aber nur, wenn die Datei klein ist, etwa 1 MB. Als ich es mit größeren Dateien ausprobierte, wie z. B. 20 MB, zeigt mein Browser es an, anstatt es zum Download zu zwingen. Ich habe bisher viele Header ausprobiert, jetzt sieht mein Code so aus:

PrintWriter out = response.getWriter();
String fileName = request.getParameter("filename");

File f= new File(fileName);

InputStream in = new FileInputStream(f);
BufferedInputStream bin = new BufferedInputStream(in);
DataInputStream din = new DataInputStream(bin);

while(din.available() > 0){
    out.print(din.readLine());
    out.print("\n");
}

response.setContentType("application/force-download");
response.setContentLength((int)f.length());
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-Disposition","attachment;filename=\"" + "xxx\"");//fileName);

in.close();
bin.close();
din.close();

66voto

Vineet Reynolds Punkte 74302

Sie setzen die Antwortheader nach dem Schreiben des Dateiinhalts in den Ausgabestrom. Dies ist ziemlich spät im Antwortlebenszyklus, um Header zu setzen. Die richtige Reihenfolge der Operationen sollte sein, zuerst die Header zu setzen und dann den Inhalt der Datei in den Ausgabestrom des Servlets zu schreiben.

Daher sollte Ihre Methode wie folgt geschrieben werden (das wird nicht kompilieren, da es nur eine Darstellung ist):

response.setContentType("application/force-download");
response.setContentLength((int)f.length());
//response.setContentLength(-1);
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-Disposition","attachment; filename=\"" + "xxx\"");//fileName);
...
...
File f= new File(fileName);

InputStream in = new FileInputStream(f);
BufferedInputStream bin = new BufferedInputStream(in);
DataInputStream din = new DataInputStream(bin);

while(din.available() > 0){
    out.print(din.readLine());
    out.print("\n");
}

Der Grund für das Scheitern ist, dass es möglich ist, dass die tatsächlichen Header, die vom Servlet gesendet werden, von dem abweichen, was Sie senden möchten. Immerhin, wenn der Servlet-Container nicht weiß, welche Header (die vor dem Body in der HTTP-Antwort erscheinen) vorhanden sind, kann er geeignete Header setzen, um sicherzustellen, dass die Antwort gültig ist; das Setzen der Header nachdem die Datei geschrieben wurde, ist daher nutzlos und überflüssig, da der Container die Header bereits gesetzt haben könnte. Dies können Sie überprüfen, indem Sie den Netzwerkverkehr mit Wireshark oder einem HTTP-Debugging-Proxy wie Fiddler oder WebScarab betrachten.

Sie können auch die Java EE API-Dokumentation für ServletResponse.setContentType konsultieren, um dieses Verhalten zu verstehen:

Setzt den Inhaltstyp der an den Client gesendeten Antwort, wenn die Antwort noch nicht committed wurde. Der angegebene Inhaltstyp kann eine Zeichenkodierungsspezifikation enthalten, z. B. text/html;charset=UTF-8. Die Zeichenkodierung der Antwort wird nur aus dem angegebenen Inhaltstyp gesetzt, wenn diese Methode aufgerufen wird, bevor getWriter aufgerufen wird.

Diese Methode kann wiederholt aufgerufen werden, um Inhaltstyp und Zeichenkodierung zu ändern. Diese Methode hat keine Wirkung, wenn sie nachdem die Antwort committed wurde, aufgerufen wird.

...

6voto

Vladimir Dyuzhev Punkte 17849

Setzen Sie den Inhaltstyp und andere Header vor, bevor Sie die Datei ausgeben. Bei kleinen Dateien wird der Inhalt zwischengespeichert und der Browser empfängt zuerst die Header. Bei großen Dateien kommt zuerst die Daten.

4voto

f1sh Punkte 10477

Dies stammt aus einem PHP-Skript, das das Problem perfekt löst, bei jedem Browser, den ich getestet habe (FF seit 3.5, IE8+, Chrome)

header("Content-Disposition: attachment; filename=\"".$fname_local."\"");
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($fname));

Soweit ich das sehen kann, machen Sie alles richtig. Haben Sie Ihre Browsereinstellungen überprüft?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X