使用 HttpClient 进行 HTTP Post 请求需要 2 秒钟,为什么?

42
更新: 我自己找到了答案,请看下面 :-)

你好,

我正在编写一个Android应用程序,使用HTTP Post和AsyncTask在后台提交信息。 我使用org.apache.http.client包来实现这一点。 我的代码基于此示例

基本上,我的代码看起来像这样:

public void postData() {
    // Create a new HttpClient and Post Header
    HttpClient httpclient = new DefaultHttpClient();
    HttpPost httppost = new HttpPost("http://192.168.1.137:8880/form");

    try {
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
        nameValuePairs.add(new BasicNameValuePair("id", "12345"));
        nameValuePairs.add(new BasicNameValuePair("stringdata", "AndDev is Cool!"));
        httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

        // Execute HTTP Post Request
        HttpResponse response = httpclient.execute(httppost);

    } catch (ClientProtocolException e) {
     Log.e(TAG,e.toString());
    } catch (IOException e) {
     Log.e(TAG,e.toString());
    }
}
问题在于httpclient.execute(..)行需要大约1.5到3秒钟,我不明白为什么。只是用HTTP Get请求页面大约需要80毫秒左右,所以问题似乎不是网络延迟本身。
问题似乎也不在服务器端,我还尝试了将数据POST到http://www.disney.com/,结果也很慢。当我在本地服务器上POST数据时,Firebug显示响应时间为1毫秒。
这在模拟器上和我的Nexus One上都发生了(均使用Android 2.2)。
如果您想查看完整代码,我已经将其放在GitHub上。
这只是一个使用AsyncTask在后台执行HTTP Post的虚拟程序,通过按下按钮来触发它。这是我的第一个Android应用程序,也是我很长一段时间以来的第一个Java代码。顺便说一句,这也是我在Stackoverflow上的第一个问题 ;-)
有什么想法为什么httpclient.execute(httppost)会如此缓慢吗?

我遇到了完全相同的问题,只不过更糟糕。甚至可能需要20秒以上才能完成一个HttpPost。我尝试了你的修复方法,但好像没有帮助。 - theblang
2个回答

55

好的,我通过进一步的调查解决了这个问题。我所需要做的就是添加一个参数来将HTTP版本设置为1.1,如下所示:

HttpParams params = new BasicHttpParams();
params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
HttpClient httpclient = new DefaultHttpClient(params);

我发现这个方法是通过and-bookworm的HttpHelper类以及一些试错找到的。

如果我没记错,HTTP 1.0为每个请求打开一个新的TCP连接。这能解释为什么会有很大的延迟吗?

现在,在WLAN上进行HTTP POST请求需要花费50到150毫秒,而在3G上需要花费300到500毫秒左右。


2
稍微简化一下(但等价的):HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); - Yaniv Inbar
12
与其使用版本变通方法——那个为什么有效呢?——我建议采用更直接的解决方案,即 httppost.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);。请注意,我的翻译尽可能保留了原文的意思和语气,同时更加通俗易懂。 - Liudvikas Bukys
1
兄弟,我在测试我的应用程序时随意搜索了一下这个主题,因为它非常缓慢 - 这个改变让它飞快起来了。谢谢你。 - bsautner
我也遇到了这个问题,将http版本设置为1.1可以稍微改善一下。使用HttpURLConnection代替,它非常快。 - Lei Guo
1
@pabelu 我猜我是在试图解决其他问题时偶然发现了这个问题...而且显然很晚了...但我想当你说HTTP/1.0确实为每个新请求创建一个新连接时,你是非常正确的。这是HTTP/1.1中的一项重大变化,其中引入了“持久连接”的概念,除非明确说明,否则不会断开连接。请参考[RFC](http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html) - qre0ct

6

我不在使用安卓系统,但是我在Windows平台上使用httpclient 4.0.1时遇到了完全相同的问题。经过一番苦思冥想,我找到了解决方案。

HttpParams params = new BasicHttpParams();
//this how tiny it might seems, is actually absoluty needed. otherwise http client lags for 2sec.
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpClient httpClient = new DefaultHttpClient(params);
HttpResponse httpResponse;


HttpPost httpPost = new HttpPost("http://"+server+":"+port+"/");
StringEntity entity = new StringEntity(content, "utf-8");
entity.setContentType("text/plain; charset=utf-8"); 
httpPost.setEntity(entity);

httpResponse=httpClient.execute(httpPost);

String response = IOUtils.toString(httpResponse.getEntity().getContent(),encoding);
httpResponse.getEntity().consumeContent();

httpClient.getConnectionManager().shutdown();
return(response);

我不知道为什么使用HTTP1.1版本设置参数可以解决问题,但它确实可以。 更奇怪的是,如果执行HTTP Get请求,则不会显示症状。
总之,我希望这对某些人有所帮助!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接