Как заставить браузер загрузить файл?


все работает нормально, но только если файл маленький, около 1 МБ, когда я пробовал его с большими файлами, например 20 МБ мой браузер отображает его, вместо того, чтобы загружать, я пробовал много заголовков до сих пор, теперь мой код выглядит:

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();
3   51  

3 ответа:

вы устанавливаете заголовки ответов после записи содержимого файла в выходной поток. Это довольно поздно в жизненном цикле ответа, чтобы установить заголовки. Правильная последовательность операций должна состоять в том, чтобы сначала установить заголовки, а затем записать содержимое файла в выходной поток сервлета.

поэтому ваш метод должен быть записан следующим образом (это не будет компилироваться, поскольку это просто представление):

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");
}

причиной сбоя является то, что возможно для фактических заголовков, отправленных сервлетом, будет отличаться от того, что вы собираетесь отправить. В конце концов, если контейнер сервлета не знает, какие заголовки (которые появляются перед телом в ответе HTTP), то он может установить соответствующие заголовки, чтобы убедиться, что ответ действителен; поэтому установка заголовков после записи файла бесполезна и избыточна, поскольку контейнер, возможно, уже установил заголовки. Вы можете подтвердить это, посмотрев на сеть трафик с использованием Wireshark или прокси-сервера отладки HTTP, такого как Fiddler или WebScarab.

вы также можете обратиться к документации Java EE API для ServletResponse.setContentType чтобы понять такое поведение:

задает тип содержимого ответа, отправляемого клиенту, если ответ еще не зафиксированы. данный тип контента может включать в себя спецификацию кодировки символов, например, text/html;charset=UTF-8. Этот кодировка символов ответа устанавливается только из данного типа контента, если этот метод вызывается до вызова getWriter.

этот метод может быть вызван несколько раз, чтобы изменить тип контента и кодировку. этот метод не действует, если вызывается после фиксации ответа.

...

установить content-type и другие заголовки до вы записываете файл. Для небольших файлов содержимое буферизуется, и браузер сначала получает заголовки. Для больших данные на первом месте.

Это из php-скрипта, который отлично решает проблему с каждым браузером, который я тестировал (FF с 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));

Так что, насколько я вижу, вы все делаете правильно. Вы проверили настройки Вашего браузера?