2015-12-14 12 views
8

Ich verwende Android-Universal-Image-Loader, um Bilder von Remote-Server über HTTPS auf meiner Android-Anwendung zu laden. Um Zugriff auf Bilder zu erhalten, sollte der Client ein gültiges Token bereitstellen und manchmal kann der Server den Fehler "abgelaufenes crsf-Token" zurückgeben. Um dieses Verhalten zu behandeln, sollte ein benutzerdefinierter ImageDownloader definiert werden. Unten ist die grundlegende Implementierung der Methode, die in meiner Implementierung überschrieben werden sollte.Möglichkeiten, einen InputStream Proxy

protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException { 
    HttpURLConnection conn = createConnection(imageUri, extra); 

    int redirectCount = 0; 
    while (conn.getResponseCode()/100 == 3 && redirectCount < MAX_REDIRECT_COUNT) { 
     conn = createConnection(conn.getHeaderField("Location"), extra); 
     redirectCount++; 
    } 

    InputStream imageStream; 
    try { 
     imageStream = conn.getInputStream(); 
    } catch (IOException e) { 
     // Read all data to allow reuse connection (http://bit.ly/1ad35PY) 
     IoUtils.readAndCloseStream(conn.getErrorStream()); 
     throw e; 
    } 
    if (!shouldBeProcessed(conn)) { 
     IoUtils.closeSilently(imageStream); 
     throw new IOException("Image request failed with response code " + conn.getResponseCode()); 
    } 

    return new ContentLengthInputStream(new BufferedInputStream(imageStream, BUFFER_SIZE), conn.getContentLength()); 
} 

Ich möchte es umschreiben, um ungültige Token-Fehler zu behandeln. Wenn der Server beispielsweise einen solchen Fehler zurückgibt, sollte er erkannt werden, das Token sollte neu generiert und die Anforderung wiederholt werden.

Die einzige Lösung, die ich mit oben kommen ist wie diese (verkürzte Code):

imageStream = conn.getInputStream(); 
byte[] body = org.apache.commons.io.IOUtils.toByteArray(imageStream); 
if (body.length < 300 // high probability to contain err message 
      && isInvalidToken(body)) { 
       // handle error 
} 
return new ByteArrayInputStream(body); 

Ist sicher eine solche Art von Lösung zu verwenden, wenn man bedenkt ich es für Thumbnails von max 80kb Größe nur benutzen? Gibt es andere Lösungen?

Antwort

3

Ihre Lösung ist sicher, obwohl es schöner ist, wenn Sie Ihre ImageDownloaderInputStream Klasse erstellen, die InputStream implementiert und die ursprüngliche umschließt. Sie können einige Chunks aus dem zugrunde liegenden Eingabestream vorab laden (puffern), um festzustellen, ob der Inhalt gültig ist oder nicht.

Die einzige Methode, die Sie überschreiben sollten, ist read().

Wenn der Inhalt gültig ist, können Sie den Pufferinhalt dem Aufrufer bereitstellen, wenn der Puffer leer ist, direkt aus dem zugrunde liegenden InputStream streamen.

Wenn der Inhalt ungültig ist, lesen Sie einfach einen anderen Stream oder geben Sie einen Null-Länge-Stream zurück.

public class ImageDownloaderInputStream implements InputStream { 
    private byte[] buffer = null; 
    private int bufLen = 0; 
    private int bufIndex = 0; 
    private boolean isContentValid; 
    private InputStream wrapped; 

    public ImageDownloaderInputStream (InputStream wrapped) { 
     this.wrapped = wrapped; 
    } 

    @Override 
    public ind read() { 
     if(buffer == null) { 
      // check content and fill buffer 
      this.isContentValid = checkContent(); 
     } 
     if (this.isContentValid) { 
      if(bufIndex < bufLen) { 
       return buffer[bufIndex++] & 0xFF; 
      } else { 
       return wrapped.read(); 
      } 
     } else { 
      // error handling: zero-length stream 
      return -1; 
     } 
    } 

    private boolean checkContent() { 
     // fill the buffer 
     this.buffer = new byte[1024]; 
     this.bufLen = wrapped.read(this.buffer); 
     // read more if not enough 

     // check the content 
     return true; 
     // return false;  
    } 
} 
+1

Danke, dies scheint einer der 'richtigen' Wege zu sein, die beschriebene Aufgabe zu implementieren. – bvk256

0

Haben Sie so etwas in Erwägung gezogen?

if(conn.getResponseCode()==HttpStatus.RESPONSE_OK) else{ //repeat request...} 
+0

Das Problem ist, wenn ein ungültiger Token Server antwortet mit 200 OK, nur der Körper der HTTP-Antwort wird den Fehler anzeigen. – bvk256

1

Sie für ein gültiges Token überprüfen können, nachdem Sie, dass die Antwort überprüft 200 OK wie so war:

conn.getResponseCode() == HttpStatus.RESPONSE_OK && isValidToken(body) 

Werden diese Bedingungen dann nicht erfüllt Sie behandeln sie entsprechend dh die Anforderung x-mal wiederholen .

Ich würde in Betracht ziehen, eine isValidToken(...) Methode anstelle Ihrer isInvalidToken(...) zu haben, so dass Sie die Antwort der Methode nicht negieren müssen.