2010-10-04 18 views
0

J'utilise trois servlets pour servir des fichiers à télécharger:servlet Java: problème avec fichier corrompu télécharger

  • ByteArrayDownloadServlet: utilisé pour les petits fichiers, tels que les rapports ou les fichiers de base de données
  • FileDownloadServlet: utilisé pour les petites des fichiers volumineux
  • MultipleFileDownloadServlet: créer un zip avec les fichiers demandés et le diffuser

Ils sont basés dans la mise en œuvre suivante: link text

J'ai reçu plusieurs plaintes au sujet de téléchargements corrompus. Le problème est que je ne peux pas simuler ou trouver un modèle dans les erreurs:

  • parfois avec de gros fichiers
  • parfois lorsque l'utilisateur demande plus d'un fichier à télécharger et un fichier zip et est créé dynamiquement
  • parfois avec des fichiers plus petits, mais qui sont demandées par de nombreux utilisateurs simultanément

Dans ce poste mentionné ci-dessus commentaires il y a des gens ayant signalé des problèmes similaires, mais pas de solution. Je lis aussi beaucoup de fils d'ici et plus je me suis rapproché: link text

Est-ce que quelqu'un a rencontré un problème similaire ou a un code d'exemple qui fonctionne?

Merci, Felipe

@Override 
@SuppressWarnings("unchecked")  
protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException 
{ 
    HttpSession session = request.getSession(); 
    List<File> selectedFileList = (List<File>) session.getAttribute("selectedFileList"); 

    if(selectedFileList == null) 
    { 
     response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED, "Lista de arquivos não informada"); 
     return; 
    } 

    response.reset(); 
    response.setContentType("application/zip");   

    response.setHeader("Content-Disposition", "attachment; filename=\"" 
     + "atualizacoes_" 
     + new Date().getTime() + ".zip" + "\""); 

    ZipOutputStream output = null; 

    try 
    { 
     output = new ZipOutputStream(response.getOutputStream()); 

     for(File file : selectedFileList) 
     { 
      InputStream input = new FileInputStream(file); 
      output.putNextEntry(new ZipEntry(file.getName()));     

      byte[] buffer = new byte[DownloadHandler.DEFAULT_BUFFER_SIZE]; 
      int length; 
      while((length = input.read(buffer)) > 0) 
      { 
       output.write(buffer, 0, length); 
      } 

      output.closeEntry(); 
      input.close(); 
     }    

    output.finish(); 
    output.flush(); 
    output.close(); 
    } 
    catch(Exception e) 
    { 
     if(!(e instanceof ClientAbortException)) 
     { 
      new ExceptionMail(getClass().getSimpleName(), e); 
     } 
    } 
    finally 
    {    
     session.removeAttribute("selectedFileList");   
    } 
+1

vous avez finalement découvert BalusC: http://stackoverflow.com/users/157882/balusc –

+1

Qu'en est-il l'original 'FileServlet' avez-vous changé? Il est difficile de savoir exactement ce qui ne va pas sans code ou autres détails. –

Répondre

2

Les causes les plus fréquentes pour les téléchargements au hasard corrompus d'un servlet est que la servlet n'est pas threadsafe et/ou qu'il est en train de lire des octets en tant que caractères. Le partage de requêtes ou de données basées sur une session entre des demandes dans la même session ou le même contexte servlet est également une cause possible de ce problème.

+0

Pouvez-vous donner plus de détails à ce sujet? Merci – FkJ

+0

Une servlet n'est pas threadsafe lorsqu'elle affecte des données de portée de requête ou de session en tant que variable d'instance de servlet qui est utilisée dans le bloc de méthode. Streaming octets ne devrait pas être fait en utilisant 'Reader' ou' Writer'. – BalusC

+0

J'ai joint mon servlet de téléchargement de fichiers multiples. Je n'utilise pas de variables d'instance. Est-ce que je manque quelque chose? Merci – FkJ

0

Vous ne devez pas fermer le flux de sortie car il est géré par le conteneur de servlet. Je ne suis pas sûr de la couleur.

+0

Cela ne causerait pas de téléchargements corrompus. Connexes: http://stackoverflow.com/questions/1829784/should-i-close-the-servlet-outputstream/1829823#1829823 – BalusC

+0

Oui mais c'est une mauvaise pratique. Aussi, vous devez définir l'en-tête content-length à votre réponse – ehsavoie

+0

C'était juste votre propre code qui l'a fait. Lisez attentivement le lien donné. – BalusC

0

Vous avez un flux sérieux dans votre code en dessous des lignes.

int length; 
     while((length = input.read(buffer)) > 0) 
     { 
      output.write(buffer, 0, length); 
     } 

Votre «entrée» est un droit FileInputStream? Comment pouvez-vous vous assurer que FileInputStream a toujours plus de 0 octets disponibles tout au long de votre itération? Au lieu de cela, il doit être écrit comme ci-dessous.

int length; 
     while((length = input.read(buffer)) != -1) 
     { 
      output.write(buffer, 0, length); 
     }