来自HttpClient的重复请求

时间:2012-01-21 00:06:06

标签: android httpclient

我在Android上使用HttpClient 4.0.1 ...我发出了一个POST请求,其头标设置为当前的毫米...我看到该请求在几毫秒(5-10)的范围内两次命中服务器彼此..但我设置的标题对于两个请求都是相同的。这种情况非常偶然发生......我看到wireshark中的请求之间没有真正的区别......我不知道这是怎么发生的。有人之前遇到过这个或者有关于如何进一步调试它的任何提示吗?

这是我用来创建客户端的代码:

public static HttpClient getAndroidHttpClient(final int timeOut) {
    // set up the schemas
    SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));

    // set up our params
    HttpParams params = new BasicHttpParams();
    params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeOut);
    params.setIntParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, timeOut);
    params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, timeOut);
    params.setLongParameter(ConnManagerPNames.TIMEOUT, timeOut);
    params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 1);
    params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(1));
    params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);

    HttpProtocolParams.setUserAgent(params, "android-client-v1.0");
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
    HttpProtocolParams.setContentCharset(params, "utf8");

    ThreadSafeClientConnManager conman = new ThreadSafeClientConnManager(params, schemeRegistry);

    DefaultHttpClient defaultHttpClient = new DefaultHttpClient(conman, params);

    return defaultHttpClient;
}

3 个答案:

答案 0 :(得分:19)

所以这里似乎发生的是你的客户端发送请求,没有及时得到响应,结果再次重试相同的请求(应该如此)。反过来,这会导致多个POST请求被发送到您的服务器(几乎连续),您的服务器当前无法正确处理这些请求。

要验证/调试此问题,请尝试按如下方式禁用HTTP重试:

defaultHttpClient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler
                                             (0, false));

这当然会处理您的重复请求问题,但随后会引入另一个更严重的问题;也就是说,它会尝试一次(只有一次)并失败。根据您从评论中获得的信息,您可以尝试以下几个想法:

请使用伪代码,因为我没有关于客户端架构的所有细节

连续处理多个帖子

  • 禁用自动重试(如上所述)
  • POST个请求换成类似于this实施方式的循环
  • 然后在手动重试之间sleep或实施您的exponential backoff
  • 版本

无论如何,您的服务器需要以合理的方式处理重复请求的功能,这是HTTP的后续。但是,你至少有机会在重复轰炸之前处理第一个。

我建议处理请求时的第一个步骤是设置某种形式的(重复)标志。然后,如果/当它收到一个欺骗,它继续处理第一个请求(像往常一样)并默默地忽略欺骗。

总而言之,整个计划的重点是让您的服务器有机会设置欺骗标志。之后,根据需要丢弃(或处理)重复请求是您服务器的工作。这一切都有意义吗?

答案 1 :(得分:1)

我不能代表Android附带的HttpClient版本,因为它现在基于一个非常古老的BETA前快照实际上是一个分支。但是,如果您使用的是Apache HttpClient 4.x的库存版本,则不会会自动重试POST或PUT请求,除非另有配置。

在您的特定情况下,我怀疑由于连接丢失或类似的网络问题,无线驱动程序会重新传输HTTP消息。 HTTP不是保证传递协议。 HTTP消息可以由较低级别的传输重新发送。您的应用程序必须准备好处理重复的HTTP消息。

答案 2 :(得分:0)

重试政策我们可以自定义

WITH VOLLEY REQUEST

  

stringRequest.setRetryPolicy(new DefaultRetryPolicy(                   0,                   DefaultRetryPolicy.DEFAULT_MAX_RETRIES,                   DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));     volleySingleton.addToRequestQueue(stringRequest);