我使用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;
}
稍后我会执行以下操作来阅读输入流
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()));
}
它生成以下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
Connection标头是“关闭”但我仍然无法读取整个响应。知道我做错了什么吗?
答案 0 :(得分: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,并且在此过程中它将阻塞并等待网络。读取数组也比使用单个字节更高效。
答案 1 :(得分:0)
也许我错过了,但你的代码中“输入”的数据类型是什么?一般来说,关于InputStreams的一些奇怪的事情是read(...)方法往往会阻塞,直到数据可用,然后只返回那些数据。实际上,您需要继续读取InputStream并附加到ByteArrayInputStream或其他结构,直到您明确强制执行EOFException。
答案 2 :(得分: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;
}