2011-02-04 4 views
10

ho problemi con il caricamento di immagini in android.HTTP httpclient file upload corruzione dei dati e problemi di timeout

sto usando Apache 4.1 httpmime lib il codice è come questo:

MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE); 

reqEntity.addPart("image", new FileBody(new File(AndorraApplication.getPhotosPath() + "/" + entity.getFileName()), "image/jpeg")); 
resp = NetworkUtils.sendHttpRequestMultipart(EXPORT_PHOTOS_URI, reqEntity); 

NetworkUtils classe:

public class NetworkUtils { 
    public static final int REGISTRATION_TIMEOUT = 3 * 1000; 
    public static final int WAIT_TIMEOUT = 5 * 1000; 

    public static HttpResponse sendHttpRequestMultipart(String uri, MultipartEntity entity) { 
     HttpClient mHttpClient = new DefaultHttpClient(); 
     final HttpParams params = mHttpClient.getParams(); 
     HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT); 
     HttpConnectionParams.setSoTimeout(params, WAIT_TIMEOUT); 
     ConnManagerParams.setTimeout(params, WAIT_TIMEOUT); 

     HttpPost post = new HttpPost(uri); 
     post.addHeader(entity.getContentType()); 
     post.setEntity(entity); 
     HttpResponse resp = mHttpClient.execute(post); 
    } 
} 

a volte tutto funziona bene, ma a volte (soprattutto su una connessione lenta) l'immagine è stata caricata molto corrotta. l'esempio è qui: http://pixelbirthcloud.com/574_orig.jpg

non presenta eccezioni. la lunghezza del file caricato è uguale a quella originale .. ho provato a cambiare il tipo mime in application/octet-stream o rimuoverlo del tutto. prova a giocare con i timeout. ancora lo stesso risultato. gli utenti finali caricano quasi sempre immagini danneggiate (anche se sono riuscito a ottenere immagini bronz solo 2 volte) .. le dimensioni dell'immagine erano inizialmente di 2,5 mega, ma poi l'ho ridotta a 500-700 kb. non ha risolto il problema però.

non ho provato a cambiare la libreria di apache .. forse è il problema .. ma per quanto ho letto la rete, nessuno lo stava vivendo con la libreria httpmime.

cosa può essere? Sono completamente perso ora :(

l'altra questione è che a volte i timeout non funzionante

come quando si tratta di questa linea:. HttpResponse resp = mHttpClient.execute (post); e ho disattivare il 3G collegamento solo attende come 17-20 minuti invece di 3 o 5 secondi .. e solo poi getta eccezione provato diversi metodi come questo:..

 HttpParams params = new BasicHttpParams(); 
     HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 
     HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); 
     HttpProtocolParams.setUseExpectContinue(params, false); 
     HttpConnectionParams.setConnectionTimeout(params, 10000); 
     HttpConnectionParams.setSoTimeout(params, 10000); 
     ConnManagerParams.setMaxTotalConnections(params, 5); 
     ConnManagerParams.setTimeout(params, 30000); 

     SchemeRegistry registry = new SchemeRegistry(); 
     registry.register(new Scheme("http",PlainSocketFactory.getSocketFactory(), 80)); 
     registry.register(new Scheme("https",PlainSocketFactory.getSocketFactory(), 80)); 
     ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(params, registry); 
     HttpClient httpclient = new DefaultHttpClient(manager, params); 

ma ancora non funziona :)

risposta

7

Guarda il mio Codice di Image Uploader e ha funzionato benissimo per me Questa classe carica un file sul server e alla fine legge anche la risposta XML. Filter il codice secondo il vostro requisito .. Ha funzionato abbastanza liscio per me


package com.classifieds; 

import java.io.DataOutputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.IOException; 

import java.net.HttpURLConnection; 
import java.net.MalformedURLException; 
import java.net.URL; 

import javax.xml.parsers.ParserConfigurationException; 
import javax.xml.parsers.SAXParser; 
import javax.xml.parsers.SAXParserFactory; 

import org.xml.sax.Attributes; 
import org.xml.sax.InputSource; 
import org.xml.sax.SAXException; 
import org.xml.sax.XMLReader; 
import org.xml.sax.helpers.DefaultHandler; 


import android.util.Log; 

public class Uploader 
{ 

    private String Tag = "UPLOADER"; 
    private String urlString ;//= "YOUR_ONLINE_PHP"; 
    HttpURLConnection conn; 
    String exsistingFileName ; 

    private void uploadImageData(String existingFileName , String urlString) 
    { 
     String lineEnd = "\r\n"; 
     String twoHyphens = "--"; 
     String boundary = "*****"; 
     try { 
      // ------------------ CLIENT REQUEST 

      Log.e(Tag, "Inside second Method"); 

      FileInputStream fileInputStream = new FileInputStream(new File(
        exsistingFileName)); 

      // open a URL connection to the Servlet 

      URL url = new URL(urlString); 

      // Open a HTTP connection to the URL 

      conn = (HttpURLConnection) url.openConnection(); 

      // Allow Inputs 
      conn.setDoInput(true); 

      // Allow Outputs 
      conn.setDoOutput(true); 

      // Don't use a cached copy. 
      conn.setUseCaches(false); 

      // Use a post method. 
      conn.setRequestMethod("POST"); 

      conn.setRequestProperty("Connection", "Keep-Alive"); 

      conn.setRequestProperty("Content-Type", 
        "multipart/form-data;boundary=" + boundary); 

      DataOutputStream dos = new DataOutputStream(conn.getOutputStream()); 

      dos.writeBytes(twoHyphens + boundary + lineEnd); 
      dos 
        .writeBytes("Content-Disposition: post-data; name=uploadedfile;filename=" 
          + exsistingFileName + "" + lineEnd); 
      dos.writeBytes(lineEnd); 

      Log.v(Tag, "Headers are written"); 

      // create a buffer of maximum size 

      int bytesAvailable = fileInputStream.available(); 
      int maxBufferSize = 1000; 
      // int bufferSize = Math.min(bytesAvailable, maxBufferSize); 
      byte[] buffer = new byte[bytesAvailable]; 

      // read file and write it into form... 

      int bytesRead = fileInputStream.read(buffer, 0, bytesAvailable); 

      while (bytesRead > 0) { 
       dos.write(buffer, 0, bytesAvailable); 
       bytesAvailable = fileInputStream.available(); 
       bytesAvailable = Math.min(bytesAvailable, maxBufferSize); 
       bytesRead = fileInputStream.read(buffer, 0, bytesAvailable); 
      } 

      // send multipart form data necesssary after file data... 

      dos.writeBytes(lineEnd); 
      dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); 

      // close streams 
      Log.v(Tag, "File is written"); 
      fileInputStream.close(); 
      dos.flush(); 
      dos.close(); 

     } catch (MalformedURLException ex) { 
      Log.e(Tag, "error: " + ex.getMessage(), ex); 
     } 

     catch (IOException ioe) { 
      Log.e(Tag, "error: " + ioe.getMessage(), ioe); 
     } 


     SAXParserFactory spf = SAXParserFactory.newInstance(); 
     SAXParser sp = null; 
     try { 
      sp = spf.newSAXParser(); 
     } catch (ParserConfigurationException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (SAXException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     // Get the XMLReader of the SAXParser we created. 
     XMLReader xr = null; 
     try { 
      xr = sp.getXMLReader(); 
     } catch (SAXException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     // Create a new ContentHandler and apply it to the XML-Reader 
     MyExampleHandler1 myExampleHandler = new MyExampleHandler1(); 
     xr.setContentHandler(myExampleHandler); 

     // Parse the xml-data from our URL. 
     try { 
      xr.parse(new InputSource(conn.getInputStream())); 
     //xr.parse(new InputSource(new java.io.FileInputStream(new java.io.File("login.xml")))); 
     } catch (MalformedURLException e) { 
      Log.d("Net Disconnected", "NetDisconeeted"); 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      Log.d("Net Disconnected", "NetDisconeeted"); 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (SAXException e) { 
      Log.d("Net Disconnected", "NetDisconeeted"); 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     // Parsing has finished. 

    } 

    public Uploader(String existingFileName, boolean isImageUploading , String urlString) { 

     this.exsistingFileName = existingFileName; 
     this.urlString = urlString; 

    } 

    class MyExampleHandler1 extends DefaultHandler 
    { 
    // =========================================================== 
    // Methods 
    // =========================================================== 

    @Override 
    public void startDocument() throws SAXException { 

    } 

    @Override 
    public void endDocument() throws SAXException { 
     // Nothing to do 
    } 

    @Override 
    public void startElement(String namespaceURI, String localName, 
       String qName, Attributes atts) throws SAXException { 


    } 

    /** Gets be called on closing tags like: 
    * </tag> */ 
    @Override 
    public void endElement(String namespaceURI, String localName, String qName) 
       throws SAXException { 


    } 

    /** Gets be called on the following structure: 
    * <tag>characters</tag> */ 
    @Override 
    public void characters(char ch[], int start, int length) { 

    } 
    } 

} 
+0

Lo script online che verrà colpito dovrebbe avere il codice per leggere il file e salvarlo sul database – Javanator

+0

potrebbe finire per fare qualcosa del genere credo ... anche se non ha risposto alla domanda, ma grazie .. ha visto tale soluzione in rete prima, ma ha deciso di andare in un modo più conveniente - utilizzando httpcomponents .. ma non è riuscito per qualche motivo :( – Alex

+0

è una classe completa abbiamo solo bisogno di passare l'URL del file e l'url di script. Cosa sarebbe più conveniente quindi questa libreria httpmime – Javanator

1

ok. Abbiamo trascorso 2 giorni a provare questo problema e ho scoperto quanto segue:
quando si utilizza tcpdump su Android, i dati non erano corrotti, MA la dimensione del pacchetto tcp era 1516, il che è molto strano, perché le normali dimensioni del pacchetto Ethernet sono 1500 e tutto più di 1516 è troppo grande.
ho modificato manualmente l'MTU in 576 (credo che sia lo standard per ppp, che in realtà è 3G) e funziona perfettamente! 150 di 150 immagini sono state caricate normalmente!

questo non risolve il problema reale, tuttavia, perché è impossibile modificare mtu su dispositivi non-root, credo, e devi cambiarlo ogni volta che si riavvia il dispositivo (o ogni volta che si apre l'interfaccia - Non sono sicuro, perché non è stato possibile trovare il modo di ottenere il valore MTU tramite ifconfig). ma almeno so dove si trova il problema.
impostazione della dimensione del chunk http su un valore inferiore (provato 300 byte) non ha influito su di esso (credo che sia perché le intestazioni http sono troppo grandi se stesse) ... quindi ...quindi nulla =)

cercherà di inviare al gruppo android-sviluppatore su google, ma la loro moderazione è troppo lento ... vedremo ...

+0

Ciao Alex, penso di avere un problema simile a te ma non ho verificato con tcpdump come hai fatto tu. Sto usando httpclient e quello che ho fatto è impostare un checksum sui dati che il client sta inviando, sul lato server il checksum è sbagliato nelle occasioni in cui si verifica questo problema. nel mio caso i dati caricati sembrano semplicemente la mancanza di parti del file. altre volte tutto funziona perfettamente. Ho visto il tuo thread su sviluppatori Android ma non sembra che tu abbia trovato una soluzione. qualsiasi cosa nuova da segnalare (oh per favore!) – dweebo

+0

se mancano parti del file, allora questo è un altro problema. se usi il media store, dovresti esaminare il bug di froyo con una lunghezza di file errata.perché se la lunghezza del file sul server è diversa, ma continua a ricevere il file, significa che la lunghezza del contenuto è sbagliata, altrimenti rifiuterebbe il caricamento a causa della diversa lunghezza del file ... – Alex

+0

Grazie Alex, noi ho verificato che i dati creati dall'app siano corretti, ma la versione che riceviamo sul server non è corretta. la dimensione del file è diversa. non stiamo usando il mediastore quindi il bug del file froyo non è un nostro problema, è qualcos'altro. verificato che questo accade solo con Android 2.2+, ma su una gamma di telefoni e gestori e sta accadendo a centinaia di nostri utenti – dweebo

4

Ho avuto lo stesso problema di corruzione su 80 % dei miei file caricati. L'emulatore non ha fallito nel caricare però. I file danneggiati erano 1k più grandi di quelli originali. Quindi ho impostato il buffer del flusso di output su 1 byte e ha iniziato a funzionare senza problemi. Alla fine ho lasciato 8 byte e non ho avuto più problemi di corruzione. Un buffer di circa 80 o 50, non riesco a ricordare, anche fallito. Non capisco qual è il problema, ma sono felice che funzioni in questo modo. Questa pagina è stata così stimolante, grazie.