2010-06-14 74 views
7

我使用HttpURLConnection来执行HTTP POST,但我不总是收回完整的响应。我想调试这个问题,但是当我逐步浏览它的每一行时,它就起作用了。我认为它必须是一个时间问题,所以我添加了Thread.sleep,它确实使我的代码正常工作,但这只是一个临时解决方法。我不知道为什么会发生这种情况,以及如何解决。这里是我的代码:HttpURLConnection不会读取整个响应

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; 

} 

后,我做了以下读取输入流

 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())); 
     } 

它genearates以下HTTP头

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 

其他职位有人建议把off使用

http.keepAlive=false 

系统属性,我想,和标题改为

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 

连接头是“接近”,但我仍无法读取整个响应。任何想法我做错了什么?

+1

您的问题存在歧义。 *你在谈论哪个*回应?有了这整个代码,你实际上没有阅读回应,但创建了一个请求。你使用底部的'h.getInputStream()'来读取它的响应,但是你实际上忽略了它并且/或者不显示你如何处理它。 – BalusC 2010-06-14 15:03:36

+0

Hi BalusC 我添加了缺少的部分:) – 2010-06-14 15:27:56

回答

14

我觉得你的问题是在这条线:

while (is.available() > 0) { 

据javadoc的,available不会阻止,等到所有的数据是可用的,所以你可能会得到第一个数据包,然后将返回false 。从InputStream读取正确的方法是这样的:

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

读取将返回-1时,有没有在左边的InputStream或连接被关闭,它会阻止和等待网络,而这样做。读取数组也比使用单个字节更高效。

+0

嗨Jörn 这就是问题我确定在HTTP传输层面上有什么东西可以读取,因此请阅读HttpURLConnection的整个JavaDoc,并且没有关注InputStream 谢谢! 彼得 – 2010-06-14 16:14:02

+0

哦,忘了提及的错误不仅在我的代码,而且Sun的JAXB也是如此。本来我将InputStream直接传递给 \t Object o = unmarshaller.unmarshal(bis); 其中unmarshaller是instanceof javax.xml.bind.Unmarshaller,它导致了同样的问题。 – 2010-06-14 16:20:45

0

也许我错过了,但代码中的“输入”数据类型是什么?一般来说,对InputStreams有点奇怪的是read(...)方法在数据可用之前会阻塞,然后只返回那些数据。你实际上需要继续阅读你的InputStream,并附加到ByteArrayInputStream或其他结构,直到你显式地强制一个EOFException。

+1

它可能是一个代表查询字符串的String。另请参阅[如何使用URLConnection](http://stackoverflow.com/questions/2793150/how-to-use-java-net-urlconnection-to-fire-and-handle-http-requests)。 – BalusC 2010-06-14 15:06:32

+0

嗨Curtis我编辑我的帖子,包括方法签名解释什么输入和代码snipplet读取InputStream – 2010-06-14 15:17:50

+0

'直到你明确强制EOFException'。但是如果您调用read()或readLine(),则不会得到一个。当为任何其他X调用readXXX()时,您只会得到EOFException。read()方法在EOS返回-1。JörnHorstmann的回复中的代码示例是正确的技术。 – EJP 2010-06-15 07:21:46

0

如果您正在阅读整个消息,则可以比较isr.available()和预期的内容长度。这就是我的做法:

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; 
}