сервлет: открытие нового окна с ошибкой http 404 с IE6 при загрузке файла (но файл загружен) - PullRequest
1 голос
/ 17 марта 2010

Я использую сервлет для загрузки файла с сервера на компьютер. Сервлет обрабатывает MIME-тип и прочее, затем запускает диалоговое окно, что делать с файлом (открыть, сохранить, отменить). Он работает правильно при использовании в FireFox, но при использовании с IE6 мой файл загружается, но я получил новое окно с URL моего сервлета и с ошибкой 404. Я смотрю в Интернете, но не нашел ни малейшего понятия, почему.

Вот мой код, если он поможет:

public void doGet(  HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
// envoi du fichier
BufferedInputStream bIn = null;
BufferedOutputStream bOut = null;
int bytesRead;
byte[] buffer = new byte[2048];
try {
    String nomFichier = <my_filename>;
    // encodage des caractères hors [a-Z, 0-9] pis transformation des espace(+) pour l'URL
    String path = <my_path_to_download> + StringUtils.replace(URLEncoder.encode(nomFichier, "UTF-8"), "+", "%20");

    URL url = new URL(path);
    // Test si le fichier bien présent sur le serveur
    if (((HttpURLConnection) url.openConnection()).getResponseCode() != HttpURLConnection.HTTP_OK) {
        throw new FileNotFoundException();
    }
    bIn = new BufferedInputStream(url.openStream());

    String extension = StringUtils.getFilenameExtension(nomFichier).toLowerCase();
    // choix du type MIME selon l'extension du fichier
    if (Extensions.PDF.equals(extension)) {
        res.setContentType("application/pdf");
    } else if (Extensions.WORD.equals(extension)) {
        res.setContentType("application/msword");
    } else if (Extensions.HTM.equals(extension)) {
        res.setContentType("text/htm");
    } else if (Extensions.HTML.equals(extension)) {
        res.setContentType("text/html");
    } else {
        LOGGER.error("Format de fichier non géré : " + extension);
        throw new RuntimeException("Format de fichier non géré : " + extension);
    }
    // n'ouvre pas dans le navigateur et renseigne le nom de fichier pour "Save as..."
    res.setHeader("Content-Disposition", "attachment; filename=\"" + nomFichier + "\";");

    // lecture/écriture des données
    bOut = new BufferedOutputStream(res.getOutputStream());
    while (-1 != (bytesRead = bIn.read(buffer, 0, buffer.length))) {
        bOut.write(buffer, 0, bytesRead);
    }
} catch (Exception e) {
    LOGGER.error("Erreur à la récupération du fichier " + nomFichier, e.getCause());
    res.sendError(HttpServletResponse.SC_NOT_FOUND);
} finally {
    if (bIn != null)
        bIn.close();
    if (bOut != null)
        bOut.close();
}

}

1 Ответ

1 голос
/ 17 марта 2010

Помимо нескольких вещей, которые можно сделать более эффективно (например, ServletContext#getMimeType() и т. Д.), Код выглядит хорошо (при необходимости вы можете получить некоторые идеи из этого примера ).

Проблема явно больше на стороне клиента. Невозможно получить ответ HTTP (404) без предварительного запуска HTTP-запроса. Клиент, по-видимому, запускает два HTTP-запроса на стороне сервера вместо одного. Одной из возможных причин этого является то, что вы добавили некоторую функцию Javascript в onclick ссылки или кнопку, которая не возвращает false из-за некоторой специфической ошибки IE6 в коде Javascript. Другой возможной причиной является то, что вы использовали target="_blank" в ссылке или форме, в то время как для ссылки / кнопки загрузки это совершенно не нужно. Другая причина в том, что вы использовали Javascript window.open() для запуска запроса на загрузку, хотя это также совершенно не нужно.

В конце концов просто имейте форму "простой ванили", чья action указывает на сервлет, или ссылку "простой ванили", чья href указывает на сервлет. Заголовок Content-Disposition: attachment заставит браузер открыть диалог Сохранить как . Абсолютно не нужен Javascript или атрибут target.

...