Ответ 1
Вы настраиваете заголовки ответов после записи содержимого файла в выходной поток. Это довольно поздно в жизненном цикле ответа для настройки заголовков. Правильная последовательность операций должна состоять в том, чтобы сначала установить заголовки, а затем записать содержимое файла в выходной поток сервлета.
Следовательно, ваш метод должен быть записан следующим образом (это не будет компилироваться, поскольку это простое представление):
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.
Вы также можете обратиться к документации API Java EE для ServletResponse.setContentType, чтобы понять это поведение:
Устанавливает тип содержимого ответа, отправляемого клиенту, , если ответ еще не был зафиксирован. Данный тип содержимого может включать спецификацию кодировки символов, например text/html; кодировка = UTF-8. Кодировка символов ответа устанавливается только из заданного типа содержимого, если этот метод вызывается до вызова getWriter.
Этот метод может вызываться повторно для изменения типа содержимого и кодировки символов. Этот метод не действует, если вызвано после того, как ответ был зафиксирован.
...