Получение UnknownLengthHttpInputStream при получении InputStream из HttpURLConnection в android
HttpURLConnection.getInputStream() предоставляет UnknownLengthHttpInputStream и из-за этого разбора документа выдает исключение синтаксического анализа SAX.
Ниже приведен код
try{
URL url = new URL(uri);
HttpURLConnection connection =
(HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/xml");
InputStream xml = connection.getInputStream();
System.out.println(connection.getResponseCode());
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(connection.getInputStream());
doc.getDocumentElement().normalize();
}catch(Exception e){
e.printStackTrace();
}
Любой знает причину UnknownLengthHttpInputStream. Я получаю эту ошибку только в android, и этот код отлично работает в Java Project.
Ниже приведено исключение из LogCat:
08-08 11:07:40.490: W/System.err(1493): org.xml.sax.SAXParseException: Unexpected end of document
08-08 11:07:40.504: W/System.err(1493): at org.apache.harmony.xml.parsers.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:129)
08-08 11:07:40.510: W/System.err(1493): at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:107)
08-08 11:07:40.510: W/System.err(1493): at com.example.testws.MainActivity.onCreate(MainActivity.java:59)
08-08 11:07:40.520: W/System.err(1493): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
08-08 11:07:40.520: W/System.err(1493): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
08-08 11:07:40.520: W/System.err(1493): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
08-08 11:07:40.520: W/System.err(1493): at android.app.ActivityThread.access$1500(ActivityThread.java:117)
08-08 11:07:40.530: W/System.err(1493): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
Спасибо заранее.
Ответы
Ответ 1
Вероятно, это сервер Http 1.0 (старый сервер или неправильная конфигурация) или он не поддерживается. В этом случае длина потока известна в момент закрытия соединения с сервером. Попробуйте указать http1.1 и сохранить в своем заголовке запроса (некоторые поисковые запросы помогут в этом). Только если атрибут длины содержимого указан в ответе сервера, вы будете знать длину потока заранее.
Обход проблемы:
полностью прочитайте поток http в ByteBufferStream
(пока read()
не вернет -1
). Затем бросьте ByteBufferInputStream в свою библиотеку (теперь известна длина)
Ответ 2
Вы пытались использовать библиотеки apache для этого? Я бы предложил следующее:
try {
HttpClient client = new DefaultHttpClient();
String getURL = "http://www.google.com";
HttpGet get = new HttpGet(getURL);
HttpResponse responseGet = client.execute(get);
HttpEntity resEntityGet = responseGet.getEntity();
if (resEntityGet != null) {
//do something with the response
Log.i("GET RESPONSE",EntityUtils.toString(resEntityGet));
}
} catch (Exception e) {
e.printStackTrace();
}
а затем получить поток для самого HttpEntity
.
Smth вроде:
InputStream st = entity.getContent();
Другие примеры здесь: http://www.softwarepassion.com/android-series-get-post-and-multipart-post-requests/
Ответ 3
Чтобы обработать ответ, используйте этот метод, он позаботится обо всех!!
public static ResponseHandler<String> getResponseHandlerInstance(final Handler handler) {
final ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
public String handleResponse(final HttpResponse response) {
Message message = handler.obtainMessage();
Bundle bundle = new Bundle();
StatusLine status = response.getStatusLine();
Log.d(CLASSTAG, " " + HTTPRequestHelper.CLASSTAG + " statusCode - " + status.getStatusCode());
Log.d(CLASSTAG, " " + HTTPRequestHelper.CLASSTAG + " statusReasonPhrase - " + status.getReasonPhrase());
HttpEntity entity = response.getEntity();
String result = null;
if (entity != null) {
try {
result = HTTPRequestHelper.inputStreamToString(entity.getContent());
bundle.putString("RESPONSE", result);
message.setData(bundle);
handler.sendMessage(message);
} catch (IOException e) {
Log.e(CLASSTAG, " " + HTTPRequestHelper.CLASSTAG, e);
bundle.putString("RESPONSE", "Error - " + e.getMessage());
message.setData(bundle);
handler.sendMessage(message);
}
} else {
Log.w(CLASSTAG, " " + HTTPRequestHelper.CLASSTAG + " empty response entity, HTTP error occurred");
bundle.putString("RESPONSE", "Error - " + response.getStatusLine().getReasonPhrase());
message.setData(bundle);
handler.sendMessage(message);
}
return result;
}
};
return responseHandler;
}
private static String inputStreamToString(final InputStream stream) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(stream));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
return sb.toString();
}
Ответ 4
Здесь возникает проблема, когда синтаксический анализатор SAX не может получить длину данных InputStream
. Чтобы устранить эту проблему, сохраните содержимое, прочитанное из xml
(InputStream
), в переменную String и сделайте InputStream
из переменной для метода parse
DocumentBuilder
. Для этого измените свой код следующим образом:
try {
URL url = new URL(uri);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/xml");
InputStream xml = connection.getInputStream();
DataInputStream dis = new DataInputStream(xml);
StringBuilder sb = new StringBuilder();
int asci = dis.read();
while (asci > 0) {
sb.append((char) asci);
asci = dis.read();
}
String inputXML = sb.toString();
String predefinedXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <EmotionDB></EmotionDB>";
InputStream inputStream = new ByteArrayInputStream(inputXML.getBytes());//use predefinedXML.getBytes() instead of inputXML.getBytes() for sample test
System.out.println(connection.getResponseCode());
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(inputStream);
doc.getDocumentElement().normalize();
} catch (Exception e) {
e.printStackTrace();
}
Здесь InputStream
будет иметь правильную длину содержимого, поскольку она построена из ByteArrayInputStream
с фиксированным числом байтов.
Ответ 5
Как только попробуйте это сделать
if(connection.getResponseCode() ==HttpURLConnection.HTTP_OK){
InputStream xml = connection.getInputStream();
..........
}else{
//problem in URI/connection .....
}
Ответ 6
Вам нужно будет закрыть поток вывода должным образом в службе, чтобы избежать этого исключения.
Если вы используете стороннюю библиотеку, убедитесь, что вы установили заголовок ответа
Content-Type
Content-Length
Если вы используете java-сервис, вы можете получить длину контента из метода
File.length()