Возврат файла CSV из сервлета с использованием ServletOutputStream через HTTPS в Internet Explorer - PullRequest
6 голосов
/ 23 мая 2009

У меня есть сервлет, который возвращает файл csv, который «работает» по HTTP как в Internet Explorer, так и в Firefox. Когда я выполняю тот же сервлет через HTTPS, только Firefox продолжает загружать файл CSV через HTTPS. Я не думаю, что это обязательно проблема Интернета 6 или 7, описанная на MSDN :

Сообщение:

Internet Explorer не может загрузить data.csv из интернета mydomain.com Исследователь не смог открыть это Интернет сайт. Запрашиваемый сайт либо недоступен, либо не может быть найден. Пожалуйста, попробуйте позже.

Обратите внимание, что сайт по-прежнему находится в рабочем состоянии после этого сообщения, и вы можете продолжить просмотр сайта, это всего лишь загрузка CSV, которая запрашивает это сообщение. Мне удалось получить доступ к аналогичным файлам через https в IE из других приложений j2ee, поэтому я считаю, что это наш код. Разве мы не должны закрывать bufferedOutputStream?

UPDATE

закрывать или не закрывать выходной поток: Я задал этот вопрос на форумах java posse, и обсуждение 1022 * также было проницательным. В конце концов, кажется, что ни один контейнер не должен полагаться на «клиента» (в данном случае ваш код сервлета), чтобы закрыть этот поток вывода. Таким образом, если ваша ошибка закрытия потока в вашем сервлете вызывает проблемы, это скорее отражение плохой реализации вашего контейнера сервлета, чем вашего кода. Я рассказал о поведении IDE и учебных пособий от Sun, Oracle и BEA и о том, как они также не согласуются с тем, закрывают ли они поток или нет.

О поведении, специфичном для IE : в нашем случае отдельный продукт «Oracle Web Cache» вводил дополнительные значения заголовков, которые влияют на Internet Explorer только из-за способа, которым IE реализует требование «Нет кэша» ( см. Статью MSDN ). Код:

public class DownloadServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, 
                      HttpServletResponse response) throws ServletException, 
                                                           IOException {
        ServletOutputStream out = null;
        ByteArrayInputStream byteArrayInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;
        try {
            response.setContentType("text/csv");
                        String disposition = "attachment; fileName=data.csv";
            response.setHeader("Content-Disposition", disposition);

            out = response.getOutputStream();
            byte[] blobData = dao.getCSV();

            //setup the input as the blob to write out to the client
            byteArrayInputStream = new ByteArrayInputStream(blobData);
            bufferedOutputStream = new BufferedOutputStream(out);
            int length = blobData.length;
            response.setContentLength(length);
            //byte[] buff = new byte[length];
             byte[] buff = new byte[(1024 * 1024) * 2];

            //now lets shove the data down
            int bytesRead;
            // Simple read/write loop.
            while (-1 != 
                   (bytesRead = byteArrayInputStream.read(buff, 0, buff.length))) {
                bufferedOutputStream.write(buff, 0, bytesRead);
            }
            out.flush();
            out.close();

        } catch (Exception e) {
            System.err.println(e); throw e;

        } finally {
            if (out != null)
                out.close();
            if (byteArrayInputStream != null) {
                byteArrayInputStream.close();
            }
            if (bufferedOutputStream != null) {
                bufferedOutputStream.close();
            }
        }
    }

1 Ответ

5 голосов
/ 23 мая 2009

Я действительно запутался в вашем механизме записи "от спины через грудь к голове". Почему бы не просто (поток вывода сервлета будет буфферендным, вот и все содержимое контейнера):

byte[] csv = dao.getCSV();
response.setContentType("text/csv");
response.setHeader("Content-Disposition", "attachment; filename=data.csv"));
reponse.setContentLength(csv.length);
ServletOutputStream out = response.getOutputStream();
out.write(csv);

Не должно быть необходимости очищать выходной поток или закрывать его.

Содержимое заголовка не должно анализироваться с учетом регистра IE, но кто знает: не указывайте fileName. Следующий вопрос - кодировка. CSV - это текст, поэтому вы должны использовать getWriter() или g etOutputStream() и установить тип содержимого, например, «text / csv; charset = UTF-8». Но dao должен предоставлять CSV в виде строки вместо байта [].

Код сервлета не имеет ничего общего с HTTPS, поэтому протокол не имеет значения со стороны сервера. Я надеюсь, вы можете проверить сервлет с локального хоста с помощью HTTP.

А как насчет фильтров в вашем приложении? Фильтр может также установить HTTP-заголовок (или нижний колонтитул) с контролем кэша, например.

...