HttpurlConnection لا يقرأ الاستجابة بأكملها
-
27-09-2019 - |
سؤال
أستخدم httpurlconnection للقيام بنشر HTTP لكنني لا أعود دائمًا إلى الاستجابة الكاملة. أردت تصحيح المشكلة ، لكن عندما أخطو كل سطر نجح. اعتقدت أنها يجب أن تكون مشكلة توقيت ، لذا أضفت 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
رأس الاتصال "قريب" ولكن ما زلت لا أستطيع قراءة الاستجابة بأكملها. أي فكرة ماذا أفعل خطأ؟
المحلول
أعتقد أن مشكلتك في هذا السطر:
while (is.available() > 0) {
حسب جافادوك ، available
لا يحظر وينتظر حتى تتوفر جميع البيانات ، لذلك قد تحصل على الحزمة الأولى ثم ستعود خاطئة. الطريقة الصحيحة للقراءة من inputstream هي مثل هذا:
int len;
byte[] buffer = new byte[4096];
while (-1 != (len = in.read(buffer))) {
bos.write(buffer, 0, len);
}
ستعود القراءة إلى -1 عندما لا يوجد شيء في الإدخال أو يتم إغلاق الاتصال ، وسوف يمنع الشبكة وانتظر الشبكة أثناء القيام بذلك. القراءة هي أيضا أكثر بكثير من استخدام البايتات.
نصائح أخرى
ربما فاتني ذلك ، ولكن ما نوع البيانات من "الإدخال" في الكود الخاص بك؟ شيء غريب حول inputstreams بشكل عام هو أن أساليب القراءة (...) تميل إلى حظرها حتى تتوفر البيانات ، ثم إرجاع تلك البيانات فقط. ستحتاج فعليًا إلى الاستمرار في القراءة من InputStream وإلحاقها بـ BytearRayInputStream أو بنية أخرى حتى تجبر EofException بشكل صريح.
إذا كنت تقرأ الرسالة بأكملها في وقت ما يمكنك مقارنة 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;
}