简体   繁体   English

从android中的HttpURLConnection获取InputStream时获取UnknownLengthHttpInputStream

[英]Getting UnknownLengthHttpInputStream while getting InputStream from HttpURLConnection in android

HttpURLConnection.getInputStream() gives UnknownLengthHttpInputStream and due to this Document parsing throws SAX parser exception. HttpURLConnection.getInputStream()给出UnknownLengthHttpInputStream,由于此Document解析引发SAX解析器异常。

Following is the code 以下是代码

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

Any one knows the reason for UnknownLengthHttpInputStream. 任何人都知道UnknownLengthHttpInputStream的原因。 I'm getting this error only in android and this code works perfectly in Java Project. 我只在android中遇到此错误,此代码在Java Project中完美运行。

Following is the exception from LogCat: 以下是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)

Thanks in advance. 提前致谢。

Its probably a Http 1.0 (old server or misconfiguration) server or no keep alive configured. 它可能是一个Http 1.0(旧服务器或配置错误)服务器或没有保持活动配置。 In this case the length of the stream is known at the time the connection is closed from the server. 在这种情况下,在从服务器关闭连接时,流的长度是已知的。 Try specifying http1.1 and keep-alive in your request header (some googling will help on that). 尝试在请求标头中指定http1.1和keep-alive(一些谷歌搜索将有助于此)。 Only if the content length attribute is specified in the server response, you'll know the stream length in advance. 仅当在服务器响应中指定了内容长度属性时,才会提前知道流长度。

Workaround: read the http stream into a ByteBufferStream completely (until read() returns -1 ). 解决方法:将http流完全read()ByteBufferStream (直到read()返回-1 )。 Then throw the ByteBufferInputStream to your library (length is known now) 然后将ByteBufferInputStream抛出到您的库中(现在知道长度)

Have you tried to use the apache libraries for this? 您是否尝试过使用apache库? I would suggest the following: 我建议如下:

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

and then get the stream for the HttpEntity itself. 然后获取HttpEntity本身的流。 Smth like: Smth喜欢:

InputStream st = entity.getContent();

More examples here: http://www.softwarepassion.com/android-series-get-post-and-multipart-post-requests/ 更多示例: http//www.softwarepassion.com/android-series-get-post-and-multipart-post-requests/

To handle response use this method it will take care of all !! 要处理响应使用这种方法,它将照顾所有!

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

Here the problem comes when SAX parser could not get the length of InputStream data. SAX解析器无法获得InputStream数据的长度时,问题出现了。 To fix this problem, save the contents read from the xml ( InputStream ) in to a String variable and make an InputStream from the variable for parse method of DocumentBuilder . 要解决此问题,请将从xmlInputStream )读取的内容保存到String变量中,并从DocumentBuilder parse方法的变量中创建一个InputStream To do this modify your code as follows : 为此,请按如下方式修改代码:

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

Here the inputStream will have a correct content length as it is built from a ByteArrayInputStream with a fixed number of bytes. 这里inputStream将具有正确的内容长度,因为它是从具有固定字节数的ByteArrayInputStream构建的。

Once try it like this 一旦尝试就像这样

if(connection.getResponseCode() ==HttpURLConnection.HTTP_OK){

  InputStream xml = connection.getInputStream();   
  ..........
}else{

//problem in URI/connection .....
}

You will need to close the output stream properly within the service to avoid this exception. 您需要在服务中正确关闭输出流以避免此异常。 If you are using a third party library then make sure that you have set the response header 如果您使用的是第三方库,请确保已设置响应标头

Content-Type
Content-Length

If you are using a java service you can get the content-length from method 如果您使用的是java服务,则可以从方法获取内容长度

File.length()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM