Java HttpURLConnection不会读取整个响应

Java HttpURLConnection不会读取整个响应,java,httpurlconnection,Java,Httpurlconnection,我使用HttpURLConnection进行HTTP POST,但我并不总能得到完整的响应。我想调试这个问题,但当我一步一步地完成每一行时,它都起作用了。我认为这一定是一个时间问题,所以我添加了Thread.sleep,它确实让我的代码工作了,但这只是一个临时的解决方法。我想知道为什么会发生这种情况,以及如何解决。这是我的密码: public static InputStream doPOST(String input, String inputMimeType, String url, Map

我使用HttpURLConnection进行HTTP POST,但我并不总能得到完整的响应。我想调试这个问题,但当我一步一步地完成每一行时,它都起作用了。我认为这一定是一个时间问题,所以我添加了Thread.sleep,它确实让我的代码工作了,但这只是一个临时的解决方法。我想知道为什么会发生这种情况,以及如何解决。这是我的密码:

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;

}
它生成以下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
在其他帖子中,有人建议使用

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

连接头是“close”,但我仍然无法读取整个响应。知道我做错了什么吗?

也许我错过了,但代码中“输入”的数据类型是什么?InputStreams的一个奇怪之处是read(…)方法往往会阻塞数据,直到数据可用,然后只返回该数据。实际上,在显式强制执行EOFEException之前,您需要一直从InputStream读取并附加到ByteArrayInputStream或其他结构。

我认为您的问题在于这一行:

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

当inputstream中没有剩余内容或连接已关闭时,Read将返回-1,并在执行此操作时阻塞并等待网络。读取数组的性能也比使用单个字节要好得多。

如果您同时读取整个消息,则可以将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;
}
public byte[]读取数据(HttpURLConnection conn)
抛出IOException、InterruptedException{
字符串_connlen=conn.getHeaderField(“内容长度”);
int connlen=Integer.parseInt(_connlen);
InputStream isr=null;
字节[]字节=新字节[connlen];
试一试{
isr=conn.getInputStream();
//安全计数,它不会开始挂起
int-maxcounter=0;
//等待所有数据可用,最长5秒
而((isr.available()!=connlen)和&(maxcounter<5000)){
睡眠(1);
maxcounter++;
}
//如果不能读取所有数据,则抛出
如果(最大计数器>=5000)
抛出新的非法访问错误();
//读取数据
如果(isr.read(字节,0,连接)<0)
抛出新的非法访问错误();
}最后{
如果(isr!=null)
isr.close();
}
返回字节;
}

你的问题模棱两可。你说的是哪种反应?有了这些代码,您实际上不是在读取响应,而是在创建请求。您正在使用底部的
h.getInputStream()
读取其响应,但实际上您忽略了它和/或没有显示如何处理它。嗨,BalusC,我添加了缺少的部分:)它可能是一个表示查询字符串的
字符串。另请参见。嗨,Curtis,我编辑了我的文章,其中包括解释输入是什么的方法签名和读取InputStream的代码snipplet,直到您显式强制执行EOFEException。但是如果调用read()或readLine(),则不会得到一个。当为任何其他X调用readXXX()时,只会得到EOFEException。read()方法在EOS处返回-1。Jörn Horstmann回复中的代码示例是正确的技术。嗨,Jörn,这就是问题所在。我确信HTTP传输级别上正在运行某些东西,所以请阅读HttpURLConnection的整个JavaDoc,并且没有注意InputStream,谢谢!Peteroh和忘了提到这个bug不仅在我的代码中,而且在Sun的JAXB中。最初,我将InputStream直接传递给对象o=unmarshaller.unmarshal(bis);其中unmarshaller是javax.xml.bind.unmarshaller的实例,它导致了相同的问题。
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;
}