【发布时间】:2011-09-05 13:49:12
【问题描述】:
我的 Android 应用使用 HttpURLConnection 对象从我们的服务器请求信息。服务器返回一些文本——根据请求的不同,可能是少量(约 50 个字符)或很多(12 MB)。 mime 类型是 text/plain。
在我最初的实现中,我很失望地发现 getInputStream() 正在从服务器返回整个 HTTP 响应——包括标头——尽管文档说它只包含响应主体。哦,好吧...我实现了一个小状态机来读取和存储标头,并在我的代码中提供接口以允许调用者访问标头字段。从 AsyncTask 调用它以使其脱离 UI 线程并获得简单的进度跟踪方法。一切都很好。
我最近添加了另一个从服务器请求信息的功能,所以我使用了相同的“http 连接包装器”对象,它希望在正文流中看到标头。这一次,使用 Thread 对象将下载从 UI 线程中推送出去很方便。 (我不需要进度跟踪,讽刺的是,Thread 比“便利对象”AsyncTask 更容易实现。)有趣的是,当从 Thread 对象调用时,我没有看到 getInputStream() 流中的标头。
唯一的区别是,在一种情况下,我是从派生自 AsyncTask 的对象内部发出请求,而在另一种情况下,我是从派生自 Thread 的对象内部发出请求。
当我从 AsyncTask 中使用 HttpUrlConnection 时,我会在输入流中看到标头。当我从线程中使用 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——包括传输编码被“分块”时的块长度。当我从我的线程调用时,我得到的只是 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。
【问题讨论】:
-
我也是这样。我从 Thread 发送请求,有时所有标头都在 getInputStream() 中。也在寻找解决方法。
-
@Chirag,你能告诉我为什么要使用标题。我必须从 android 验证一些凭据我在 xammp 上使用 php。我该怎么做。因为我不知道如何用 headers 编写 php 代码
标签: java android android-asynctask httpurlconnection