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

Posted

技术标签:

【中文标题】在android中从HttpURLConnection获取InputStream时获取UnknownLengthHttpInputStream【英文标题】:Getting UnknownLengthHttpInputStream while getting InputStream from HttpURLConnection in android 【发布时间】:2012-08-05 04:34:08 【问题描述】:

HttpURLConnection.getInputStream() 给出 UnknownLengthHttpInputStream 并且由于此 Document 解析引发 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)

提前致谢。

【问题讨论】:

附加来自 logcat 的异常? @Jens 我附上了来自 logcat 的异常.. 您获得了UnknownLengthHttpInputStream 流,因为您的服务器没有提供Content-Length 或使用分块传输编码。当服务器不提供任何一个时,它必须通过关闭连接来发出 HTTP 正文的结束信号——在这种情况下,它似乎在中间文档中执行。执行此调用时是否有可能嗅探 Web 服务器流量(例如使用 WireShark)? 尝试在赋值后立即打印“xml”变量。它是在控制台上打印响应还是生成错误? 对于 SOAP 调用尝试使用 KSoap2 而不是 HTTP 调用 【参考方案1】:

它可能是 Http 1.0(旧服务器或配置错误)服务器或未配置保持活动状态。在这种情况下,流的长度在从服务器关闭连接时是已知的。尝试在您的请求标头中指定 http1.1 和 keep-alive(一些谷歌搜索会有所帮助)。只有在服务器响应中指定了内容长度属性,你才会提前知道流的长度。

解决方法: 将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 本身的流。 喜欢:

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】:

曾经这样尝试过

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

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

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

【讨论】:

【参考方案5】:

SAX 解析器 无法获得InputStream 数据的长度时,问题就来了。要解决这个问题,将从xml (InputStream) 读取的内容保存到一个String 变量中,并从parseDocumentBuilder 方法的变量中创建一个InputStream。为此,请按如下方式修改您的代码:

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 构建的。

【讨论】:

【参考方案6】:

您需要在服务中正确关闭输出流以避免此异常。 如果您使用的是第三方库,请确保您已设置响应标头

Content-Type
Content-Length

如果您使用的是 java 服务,您可以从方法中获取内容长度

File.length()

【讨论】:

HTTP 协议说,在特定情况下,您可以得到没有 Content-Length 标头的响应:w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 此外,您不能总是修改您调用的服务,因为它并不总是您的。 你有什么建议的解决方案? 老实说,我认为这是因为修复了请求类型。 by connection.setRequestProperty("Accept", "application/xml"); 你可能不知道 URL 是如何响应的。

以上是关于在android中从HttpURLConnection获取InputStream时获取UnknownLengthHttpInputStream的主要内容,如果未能解决你的问题,请参考以下文章

在 Android 中从服务启动 Activity

在 Android 中从服务启动 Activity

在 android 中从 Twitter 中提取图像

在 C++ 中从 qt 获取 Android 帐户管理器

在 Android 中从 HTML 生成位图

如何在 Android 中从 Instagram 注销?