HttpURLConnection getInputStream()有时包含响应头

时间:2011-05-31 14:51:38

标签: java android android-asynctask httpurlconnection

我的Android应用使用HttpURLConnection对象从我们的服务器请求信息。服务器返回一些文本 - 可能有点(~50个字符)或很多(12 MB),具体取决于请求。 mime类型是text / plain。

在我最初的实现时,我很失望地发现getInputStream()从服务器返回整个HTTP响应 - 包括标题 - 即使文档说它只包含响应体。哦,好吧......我实现了一个小状态机来读取和存储标题,并在我的代码中提供接口,以允许调用者访问标题字段。从AsyncTask调用它以使其脱离UI线程并获得简单的进度跟踪方法。一切都很好。

我最近添加了另一个从服务器请求信息的功能,所以我使用了相同的“http连接包装”对象,它希望在正文流中看到标题。这次,使用Thread对象从UI线程推送下载很方便。 (我不需要进度跟踪,具有讽刺意味的是,Thread比“方便对象”AsyncTask更容易实现。)有趣的是,当从Thread对象调用时,我没有看到getInputStream()流中的头文件。

唯一的区别是,在一种情况下,我是从AsyncTask派生的对象内部发出请求,而在另一种情况下,我是从一个派生自Thread的对象内部发出请求。

当我从AsyncTask使用HttpUrlConnection时,我在输入流中看到了标题。当我从Thread使用HttpUrlConnection时,我只看到响应体。根据文档,后者是“正确的”行为。

我尝试过切换方法。也就是说,我在Thread而不是AsyncTask中发出第一个请求。如果我这样做,我看不到标题。当我在AsyncTask而不是Thread中发出第二个请求时,我看到输入流中只有正文所在的标题。所以这个问题似乎与我是在AsyncTask还是在一个Thread中有关。

显然,我可以选择一种或另外一种方法让我的HTTP活动脱离UI线程,但我想了解发生了什么,所以无论它如何被调用,我都可以使它的行为相同。我喜欢使用AsyncTask,因为它有一个简单的内置进度跟踪机制,但这种方法无法正常工作。

想法?建议?

更多信息

我将HttpURLConnection访问封装在一个看起来像这样的小函数中(实际代码有一个委托,它发送接收到的字符串,但我已将其简化为测试):

/**
 * Reads the data at the URL.
 * @param urlString The URL to read
 */
public void Get(
    String urlString)
    {
    URL url;
    BufferedInputStream in;
    try
        {
        url = new URL(urlString);
        conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Accept", "text/*");
        in = new BufferedInputStream(conn.getInputStream(), 8192);

        byte [] buffer = new byte[8192];
        StringBuilder stringBuffer = new StringBuilder(16384);

        int read;
        while ((read = in.read(buffer)) != -1)
            {
            String tempstr = new String(buffer, 0, read, "ISO-8859-1");
            System.out.println(tempstr);
            }
        return true;
        }
    catch (IOException e)
        {
        return false;
        }

我从两个地方调用此函数。为了测试,我有两个地方从我们的服务器请求相同的页面。首先是在一个扩展AsyncTask的对象中。在doInBackground()中,我实例化包含Get()的对象,然后调用Get()。第二个是在一个扩展Thread的对象中,我在其中实例化包含Get()的对象,然后在run()中调用Get()。在这两种情况下,我都要求使用相同的页面。

结果是当我从AsyncTask调用时,我看到所有响应头。我实际看到的是原始HTTP - 包括Transfer-Encoding“chunked”时的块长度。当我从我的线程调用时,我只得到HTML的主体,这就是我所期望的。

为了测试,我在服务器上编写了一个返回原始请求的脚本。这是我得到的(注意“awebsite”不是我服务器的名称):

在线程中运行时:

Connection: Keep-Alive
Accept: text/*
Host: www.awebsite.com
User-Agent: Java0

在AsyncTask中运行时:

[CRLF]
HTTP/1.1 200 OK
Date: Tue, 31 May 2011 23:29:20 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Content-Type: text/html
Set-Cookie: ASPSESSIONIDCQSTTQAQ=OHBIFGJCPEAAHGNHICPKOKFO; path=/
Cache-control: private
Transfer-Encoding: chunked
[CRLF]
53
Connection: Keep-Alive
Accept: text/*
Host: www.awebsite.com
User-Agent: Java0
[CRLF]
0
[CRLF]

请注意,这两种情况似乎都会发送相同的请求。但是,在我从AsyncTask调用Get()的情况下,HttpURLConnection正在向我提供响应头以及正文。

为了进一步混淆事情,访问www.google.com按预期工作 - 我从未看到标题与主体混合。所以这似乎表明在服务器端出现了问题(这让我想知道服务器是如何知道失败的)或者有一些关于服务器如何响应的信息,当它在AsyncTask中运行时会混淆HttpURLConnection。

2 个答案:

答案 0 :(得分:3)

我希望你的服务器端生成有一个错误:也许有一个响应头有几个嵌入的换行符,http解析器将它作为头的末尾。

答案 1 :(得分:0)

  1. 检查conn.getResponseCode()。如果它是-1,你不应该尝试读取流。
  2. 如果您使用的是2.1或更低版本,请执行以下操作:System.setProperty(“http.keepAlive”,“false”);
    更多细节HttpURLConnection.getResponseCode() returns -1 on second invocation