2010-06-14 16 views
7

Ich benutze HttpURLConnection, um HTTP-POST zu tun, aber ich bekomme nicht immer die volle Antwort zurück. Ich wollte das Problem beheben, aber wenn ich durch jede Zeile gehe, funktionierte es. Ich dachte, es muss ein Timing-Problem sein, also habe ich Thread.sleep hinzugefügt und es hat wirklich meinen Code funktioniert, aber das ist nur eine vorübergehende Lösung. Ich frage mich, warum das passiert und wie man es löst. Hier ist mein Code:HttpURLConnection liest nicht die ganze Antwort

public static InputStream doPOST(String input, String inputMimeType, String url, Map<String, String> httpHeaders, String expectedMimeType) throws MalformedURLException, IOException { 

    URL u = new URL(url); 
    URLConnection c = u.openConnection(); 
    InputStream in = null; 
    String mediaType = null; 
    if (c instanceof HttpURLConnection) { 

     //c.setConnectTimeout(1000000); 
     //c.setReadTimeout(1000000); 

     HttpURLConnection h = (HttpURLConnection)c; 
     h.setRequestMethod("POST"); 
     //h.setChunkedStreamingMode(-1); 
     setAccept(h, expectedMimeType); 
     h.setRequestProperty("Content-Type", inputMimeType); 

     for(String key: httpHeaders.keySet()) { 
      h.setRequestProperty(key, httpHeaders.get(key)); 

      if (logger.isDebugEnabled()) { 
       logger.debug("Request property key : " + key + "/value : " + httpHeaders.get(key)); 
      } 

     } 

     h.setDoOutput(true); 
     h.connect(); 

     OutputStream out = h.getOutputStream(); 

     out.write(input.getBytes()); 

     out.close(); 

     mediaType = h.getContentType(); 

     logger.debug(" ------------------ sleep ------------------ START"); 
     try { 
      Thread.sleep(2000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     logger.debug(" ------------------ sleep ------------------ END"); 

     if (h.getResponseCode() < 400) { 
      in = h.getInputStream(); 
     } else { 
      in = h.getErrorStream(); 
     } 
    } 
    return in; 

} 

später ich die folgenden Eingabestrom

 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     while (is.available() > 0) { 
      bos.write(is.read()); 
     } 
     is.close(); 

     //is.read(bytes); 
     if (logger.isDebugEnabled()) { 
      logger.debug(" Response lenght is : " + is.available()); 
      //logger.debug("RAW response is " + new String(bytes)); 
      logger.debug("RAW response is " + new String(bos.toByteArray())); 
     } 

Es genearates den folgenden HTTP-Header

POST /emailauthentication/ HTTP/1.1 
Accept: application/xml 
Content-Type: application/xml 
Authorization: OAuth oauth_consumer_key="b465472b-d872-42b9-030e-4e74b9b60e39",oauth_nonce="YnDb5eepuLm%2Fbs",oauth_signature="dbN%2FWeWs2G00mk%2BX6uIi3thJxlM%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1276524919", oauth_token="", oauth_version="1.0" 
User-Agent: Java/1.6.0_20 
Host: test:6580 
Connection: keep-alive 
Content-Length: 1107 

In anderen Beiträgen zu lesen vorgeschlagen wurde zu drehen aus Keep-Alive mit dem

http.keepAlive=false 

Systemeigenschaft, habe ich versucht, dass und die Header geändert

POST /emailauthentication/ HTTP/1.1 
Accept: application/xml 
Content-Type: application/xml 
Authorization: OAuth oauth_consumer_key="b465472b-d872-42b9-030e-4e74b9b60e39", oauth_nonce="Eaiezrj6X4Ttt0", oauth_signature="ND9fAdZMqbYPR2j%2FXUCZmI90rSI%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1276526608", oauth_token="", oauth_version="1.0" 
User-Agent: Java/1.6.0_20 
Host: test:6580 
Connection: close 
Content-Length: 1107 

die Verbindung Header „in der Nähe“, aber ich kann immer noch nicht die ganze Antwort lesen. Irgendeine Idee, was mache ich falsch?

+1

Es gibt Zweideutigkeit in Ihrer Frage. * Von welcher * Antwort sprichst du? Mit diesem ganzen Code lesen Sie eigentlich keine Antwort, sondern erstellen eine Anfrage. Sie lesen seine Antwort mit 'h.getInputStream()' am unteren Rand, aber Sie ignorieren es und/oder zeigen nicht, wie Sie es verarbeiten. – BalusC

+0

Hallo BalusC Ich habe die fehlenden Teile :) –

Antwort

14

Ich denke, Ihr Problem in dieser Linie ist:

while (is.available() > 0) { 

Nach dem javadoc, wird available nicht blockieren und warten, bis alle Daten zur Verfügung, so dass Sie das erste Paket bekommen könnten, und dann wird es false zurück . Der richtige Weg, von einem Inputstream zu lesen ist wie folgt:

int len; 
byte[] buffer = new byte[4096]; 
while (-1 != (len = in.read(buffer))) { 
    bos.write(buffer, 0, len); 
} 

lesen wird -1 zurück, wenn es in der Input nichts mehr übrig oder die Verbindung geschlossen ist, und es wird blockiert und für das Netzwerk warten Sie, während dies zu tun. Das Lesen von Arrays ist auch viel performanter als die Verwendung einzelner Bytes.

+0

Hallo Jörn Dies war das Problem, ich war sicher, dass etwas auf der HTTP-Transport-Ebene ist so lesen Sie den gesamten JavaDoc von HttpURLConnection, und nicht auf InputStream achten Vielen Dank! Peter –

+0

oh und vergaß zu erwähnen, der Fehler ist nicht nur in meinem Code, sondern auch Sun JAXB. Ursprünglich habe ich den InputStream direkt an \t übergeben Objekt o = unmarshaller.unmarshal (bis); wo unmarshaller ist instanceof javax.xml.bind.Unmarshaller und es ergab sich das gleiche Problem. –

0

Vielleicht habe ich es verpasst, aber was ist der Datentyp von "Eingabe" in Ihrem Code? Etwas, das an InputStreams im Allgemeinen merkwürdig ist, ist, dass die Lese (...) -Methoden dazu neigen, zu blockieren, bis Daten verfügbar sind, und dann nur diese Daten zurückzugeben. Sie müssen tatsächlich weiterhin von Ihrem InputStream lesen und an einen ByteArrayInputStream oder eine andere Struktur anhängen, bis Sie explizit eine EOFException erzwingen.

+1

Es ist wahrscheinlich ein 'String', der die Querystring darstellt. Siehe auch [So verwenden Sie URLConnection] (http://stackoverflow.com/questions/2793150/how-to-use-java-net-urlconnection-to-fire-and-handle-http-requests). – BalusC

+0

Hallo Curtis Ich habe meinen Beitrag bearbeitet, um die Methodensignatur zu beschreiben, die erklärt, was Input ist und das Code-Snipplet, das den InputStream –

+0

liest, bis Sie explizit eine EOFException erzwingen. Aber Sie erhalten keine, wenn Sie read() oder readLine() aufrufen. Sie erhalten nur EOFException, wenn Sie readXXX() für ein anderes X aufrufen. Die read() -Methoden geben bei EOS -1 zurück.Das Codebeispiel in Jörn Horstmanns Antwort ist die richtige Technik. – EJP

0

Wenn Sie die gesamte Nachricht gleichzeitig lesen, können Sie die isr.available() mit der erwarteten Inhaltslänge vergleichen. Das ist, wie ich es tat:

public byte[] readData(HttpURLConnection conn) 
     throws IOException, InterruptedException { 
    String _connlen = conn.getHeaderField("Content-Length"); 
    int connlen = Integer.parseInt(_connlen); 
    InputStream isr = null; 
    byte[] bytes = new byte[connlen]; 

    try { 
     isr = conn.getInputStream(); 

     //security count that it doesn't begin to hang 
     int maxcounter = 0; 
     //wait till all data is avalibal, max 5sec 
     while((isr.available() != connlen) && (maxcounter < 5000)){ 
      Thread.sleep(1); 
      maxcounter++; 
     } 
     //Throw if not all data could be read 
     if(maxcounter >= 5000) 
      throw new IllegalAccessError(); 

     //read the data   
     if(isr.read(bytes, 0, connlen) < 0) 
      throw new IllegalAccessError();  


    } finally { 
     if (isr != null) 
      isr.close(); 
    } 

    return bytes; 
} 
Verwandte Themen