HttpURLConnection getInputStream () иногда содержит заголовки ответа - PullRequest
2 голосов
/ 31 мая 2011

Мое приложение Android запрашивает информацию с нашего сервера с помощью объекта HttpURLConnection. Сервер возвращает некоторый текст - может быть немного (~ 50 символов) или много (12 МБ) в зависимости от запроса. Тип MIME текстовый / обычный.

После моей первоначальной реализации я был разочарован, обнаружив, что getInputStream () возвращал полный HTTP-ответ от сервера, включая заголовки, даже если в документации сказано, что он содержит только тело ответа. О, хорошо ... Я реализовал небольшой конечный автомат для чтения и хранения заголовков и предоставил интерфейсы в своем коде, чтобы позволить вызывающим абонентам получать доступ к полям заголовка. Вызывается из AsyncTask, чтобы получить его из потока пользовательского интерфейса и получить простой метод отслеживания прогресса. Все было хорошо.

Недавно я добавил еще одну функцию, которая запрашивает информацию с сервера, поэтому я использовал мой тот же объект "http connection wrapper", который ожидает увидеть заголовки в потоке тела. На этот раз было удобно использовать объект Thread, чтобы вытолкнуть загрузку из потока пользовательского интерфейса. (Мне не нужно было отслеживать прогресс, и по иронии судьбы, Thread легче реализовать, чем «удобный объект» AsyncTask.) Интересно, что я не видел заголовков в потоке getInputStream () при вызове из объекта Thread.

Единственное отличие состоит в том, что в одном случае я делаю запрос изнутри объекта, полученного из AsyncTask, а в другом случае я делаю запрос изнутри объекта, полученного из Thread.

Когда я использую HttpUrlConnection из AsyncTask, я вижу заголовки во входном потоке. Когда я использую HttpUrlConnection из потока, я вижу только тело ответа. Последнее является «правильным» поведением согласно документации.

Я пробовал переключать методы. То есть я делаю свой первый запрос в потоке вместо AsyncTask. Если я это сделаю, я не вижу заголовков. Когда я делаю свой второй запрос в AsyncTask вместо Thread, я вижу заголовки во входном потоке, где ожидается только тело. Так что проблема, похоже, связана с тем, нахожусь ли я в AsyncTask или в потоке.

Очевидно, что я мог бы выбрать один или другие методы получения своей активности HTTP из потока пользовательского интерфейса, но я хотел бы понять, что происходит, чтобы я мог заставить его вести себя одинаково независимо от того, как он вызывается. И мне нравится использовать 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 (), а затем вызываю Get () в run (). В обоих случаях я запрашиваю одну и ту же страницу.

В результате, когда я звоню из своей AsyncTask, я вижу ВСЕ заголовки ответа. То, что я на самом деле вижу, - это необработанный HTTP - включая длину чанка, когда Transfer-Encoding "чанкован" Когда я звоню из своей ветки, я получаю только тело 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]

Обратите внимание, что обе ситуации, похоже, отправляют один и тот же запрос. Однако что-то обманывает HttpURLConnection, давая мне заголовки ответа вместе с телом в случае, когда я вызываю Get () из AsyncTask.

Чтобы еще больше запутать, доступ к www.google.com работает должным образом - я никогда не вижу заголовков, смешанных с телом.Так что это может указывать на то, что на стороне сервера что-то не так (что заставляет меня задуматься, как сервер знает, что происходит сбой), или что-то в том, как сервер отвечает, сбивает с толку HttpURLConnection, когда он работает в AsyncTask.

Ответы [ 2 ]

3 голосов
/ 31 мая 2011

Я ожидаю, что в генерации вашего сервера произошла ошибка: возможно, есть заголовок ответа, который имеет пару встроенных символов новой строки, и синтаксический анализатор http принимает это как конец заголовков.

0 голосов
/ 29 июня 2011
  1. Проверьте conn.getResponseCode (). Если это -1, вы не должны пытаться читать поток.
  2. Если вы используете версию 2.1 или ниже, сделайте следующее: System.setProperty ("http.keepAlive", "false");
    Подробнее здесь HttpURLConnection.getResponseCode () возвращает -1 при втором вызове .
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...