开发者

HttpURLConnection getInputStream() sometimes contains response headers

My Android app requests information from our server using an HttpURLConnection object. The server returns some text -- could be a little (~50 characters) or a lot (12 MB) depending on the request. The mime type is text/plain.

Upon my initial implementation, I was disappointed to discover that getInputStream() was returning the entire HTTP response from the server -- including the headers -- even though the documentation said it contains only the response body. Oh well... I implemented a little state machine to read and store the headers and 开发者_如何学Goprovided interfaces in my code to allow callers to access header fields. Called it from an AsyncTask to get it off the UI thread and to get an easy progress tracking method. All was well.

I've recently added another feature that requests information from the server, so I used my same "http connection wrapper" object, which expects to see headers in the body stream. This time, it was convenient to use a Thread object to push the download off the UI thread. (I didn't need the progress tracking and ironically, Thread is easier to implement than the "convenience object" AsyncTask.) Interestingly, I was not seeing the headers in the getInputStream() stream when called from a Thread object.

The only difference is that in one case I'm making the request from inside an object derived from AsyncTask and in the other case I'm making the request from inside an object derived from Thread.

When I use HttpUrlConnection from an AsyncTask, I see headers in the input stream. When I use HttpUrlConnection from a Thread, I see only the response body. The latter is the "correct" behavior according to the documentation.

I've tried switching methods. That is, I make my first request in a Thread instead of an AsyncTask. If I do that, I do not see the headers. When I make my second request in an AsyncTask instead of a Thread, I see the headers in the input stream where only the body is expected. So the issue seems to be related to whether I'm in an AsyncTask or in a Thread.

Obviously I could choose one or the other methods of getting my HTTP activity off the UI thread, but I'd like to understand what's going on so I can make it behave identically regardless of how it's called. And I like using AsyncTask because it has an easy built-in progress tracking mechanism, but that's the method that isn't working right.

Ideas? Suggestions?

MORE INFORMATION

I've encapsulated my HttpURLConnection access in a little function that looks like this (the actual code has a delegate to which it sends the received string, but I've simplified it for testing):

/**
 * 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;
        }

I call this function from two places. For testing, I have both places requesting the same page from our server. First is in an object that extends AsyncTask. In doInBackground(), I instantiate the object that contains Get(), then call Get(). Second is in an object that extends Thread, where I instantiate the object that contains Get() then call Get() in run(). In both cases I request the same page.

The result is when I call from my AsyncTask, I see ALL the response headers. What I actually see is the raw HTTP -- including chunk lengths when Transfer-Encoding is "chunked". When I call from my Thread, I get just the body of the HTML, which is what I expect.

For testing, I wrote a script on the server that returns the raw request. Here's what I get (note "awebsite" is not the name of my server):

When running in a Thread:

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

When running in an 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]

Note that both situations seem to send the same request. However, something is tricking HttpURLConnection into giving me the response headers right along with the body in the case where I call Get() from an AsyncTask.

To further confuse things, accessing www.google.com works as expected -- I never see headers mixed with the body. So that would seem to indicate there's either something wrong on the server side (which makes me wonder how the server knows to fail) or there's something about how the server responds that confuses HttpURLConnection when it's running in an AsyncTask.


I expect there is an error in your server side generation: perhaps there is a response header that has a couple of embedded newlines and the http parser is taking that to be the end of the headers.


  1. Check conn.getResponseCode(). If it's -1 you should not try to read the stream.
  2. If you're on 2.1 or lower do the following: System.setProperty("http.keepAlive", "false");
    More details here HttpURLConnection.getResponseCode() returns -1 on second invocation.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜