Загрузка JSP - приложение / октет-поток

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

Когда пользователь щелкает, чтобы загрузить файл, веб-сервер подключается через TCP к файловому серверу. Веб-сервер загружает файл и создает HTTP-ответ для клиента.

Вот мой код:

<%@page language="java"%>
<%@page import="sun.misc.Request"%>
<%@page import="listing.ClientTCPStockage"%>
<%@page import="java.net.InetAddress"%>

<%
out.clearBuffer();

String nomFichier = request.getParameter("fichier");
String adresseStockage = request.getParameter("adresseStockage");

ClientTCPStockage clientStockage = new ClientTCPStockage(InetAddress.getByName(adresseStockage), 2004);
byte donneeFichier[] = clientStockage.getDonneesFichier(nomFichier);

response.setHeader("Content-Disposition", "attachment;filename=\"" + nomFichier + "\"");
response.setHeader("Content-Type", "application/octet-stream;");
response.setHeader("Accept-Ranges", "bytes");
response.setHeader("Content-Length", String.valueOf(donneeFichier.length));

for(int i = 0; i < donneeFichier.length; i++){
    out.write(donneeFichier[i]);
}
%>

Это отлично работает для текстовых файлов, таких как .csv или обычного .txt, но не работает для других типов, таких как .mp3 или .jpeg .. файлы в конечном итоге повреждены.

Я думаю, что проблема с моей кодировкой, но не могу найти где ..

Вот ответ HTTP-заголовка:

HTTP/1.x 200 OK
Server: Apache-Coyote/1.1
Content-Disposition: attachment;filename="test.mp3"
Accept-Ranges: bytes
Content-Type: application/octet-stream;
Content-Length: 5387668
Date: Sun, 20 Dec 2009 18:52:18 GMT

Спасибо.


person Hubert Perron    schedule 20.12.2009    source источник
comment
ClientTCPStockage подключается к файловому серверу и получает файл как byteArray. На данный момент контент действителен, потому что, когда я пытаюсь вернуть его на жесткий диск в виде файла, он работает отлично. Данные повреждаются, когда я выводю их как HTTP-ответ   -  person Hubert Perron    schedule 20.12.2009
comment
Вероятно, дубликат: см. stackoverflow.com/questions/1776142/, чтобы узнать об опасностях записи в OutputStream из JSP.   -  person skaffman    schedule 20.12.2009


Ответы (2)


Если вы вынуждены использовать jsp (а не сервлет), вы можете взглянуть на вот как -to

Он использует ServletOutputStream, который больше подходит для двоичного содержимого, чем JspWriter.

Также обратите внимание на настройки обрезки пробелов.

person Bozho    schedule 20.12.2009
comment
Ах да, out не интуитивно относится к Writer, а не к OutputStream. - person BalusC; 20.12.2009

JSP - это технология просмотра. Все, что находится за пределами скриптлетов <% %>, будет напечатано в ответ, включая символы пробела, такие как символы новой строки. Это наверняка повредит двоичные файлы.

Вы можете обрезать пробелы в файле JSP, но скриптлеты не приветствуются уже десять лет и в настоящее время считаются плохая практика. Необработанный код Java принадлежит классам Java, а не файлам JSP. Настоящее решение - использовать для этого Servlet.

Создайте класс, который extends HttpServlet, реализуйте метод doGet(), переместите код Java из файла JSP в этот метод, сопоставьте этот сервлет с определенным url-pattern, и ваша проблема должна исчезнуть. Вы можете найти здесь базовый пример такого сервлет.

Помимо этой проблемы, вы сохраняете весь файл в byte[], а не в InputStream. Я не уверен, что на самом деле делает ваш ClientTCPStockage, но я бы посоветовал исправить и это. Это потому, что каждый byte из byte[] фактически стоит одного байта памяти JVM. Представьте, что у вас есть 128 МБ памяти JVM и что более 10 пользователей одновременно запускают этот фрагмент кода с файлом размером более 12,8 МБ. Да, OutOfMemoryError.

person BalusC    schedule 20.12.2009
comment
+1 Пробел не уловил. Хотя я согласен с тем, что сервлет был бы более чистым и лучшим методом, давайте хотя бы упомянем, что OP может просто сжать первые 6 строк вместе, как это <%@page language="java"%><%@page import="sun.misc.Request"%><%@page import="listing.ClientTCPStockage"%><%@page import="java.net.InetAddress"%><%, и страница jsp, вероятно, будет работать как есть. В некоторые дни вам просто нужно сделать что-то без рефакторинга всех ваших jsps в сервлеты. :) - person Asaph; 20.12.2009
comment
Также убедитесь, что в конце файла после %> нет пробелов. - person Asaph; 20.12.2009
comment
пустое пространство не должно быть проблемой, потому что я вызываю .clearBuffer () в начале - person Hubert Perron; 20.12.2009
comment
Я хотел бы использовать сервлет, но не могу, это школьный проект, и мне нужно использовать классический JSP. Я знаю, что должен использовать MVC, сервлет, grails ... Но я не могу! - person Hubert Perron; 20.12.2009
comment
@Hubert Perron: clearBuffer() не очистит ничего, что уже было передано клиенту. И это тоже не вызовет никаких исключений (clear() будет). По крайней мере, стоит попробовать соединить вместе строчки 1-6. Сообщите нам, если это сработает. - person Asaph; 20.12.2009
comment
Избавьтесь от любых пробелов вне <% %> элементов (пробелов, новой строки и т. Д.), А также убедитесь, что ваш JSP не сохраняется вместе со спецификацией. - person BalusC; 20.12.2009
comment
@Asaph Только что попробовал, но файлы все еще повреждены. Когда я смотрю файл в редакторе, кажется, что некоторые символы заменены .. Нормальный исходный файл: PØ + «¸š6Ñ $ u $ ¦ • 1å§YI ÅÌf ± â'å7tê1õ‚ ^ o После загрузки по HTTP: P ? + ??? 6? $ U $ ?? 1 ?? YI ?? f ???? 7t? 1 ?? ^ o - person Hubert Perron; 20.12.2009
comment
@BalusC Я уверен, что слева нет пробелов / новой строки. Как я могу проверить спецификацию? - person Hubert Perron; 20.12.2009
comment
@Hubert: Ваши двоичные файлы читаются или записываются как символы. Используйте InputStream / OutputStream вместо Reader / Writer. - person BalusC; 20.12.2009