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