我在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; }
所以这里似乎发生的是你的客户端发送请求,没有及时得到响应,结果再次重试相同的请求(应该如此)。 反过来,这会导致多个POST请求被发送到您的服务器(几乎连续),您的服务器当前无法正确处理。
要validation/调试此问题,请尝试禁用HTTP重试,如下所示:
defaultHttpClient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler (0, false));
这当然会处理您的重复请求问题,但随后会引入另一个更严重的问题; 也就是说,它会尝试一次 (并且只会尝试一次)并失败。 根据您从评论中获得的信息,您可以尝试以下几个想法:
请使用伪代码,因为我没有关于客户端架构的所有细节
连续处理多个POSTS
禁用自动重试(如上所述)
将POST请求包装在类似于实现方式的循环中
然后在手动重试之间sleep或实现指数退避的版本
无论如何,您的服务器都需要能够以合理的方式处理重复请求,这是HTTP的后续。 但是,你至少有机会在重复轰炸之前处理第一个。
我建议处理请求时的第一步是设置某种forms的(重复) 标志 。 然后,如果/当它收到一个欺骗,它继续处理第一个请求(像往常一样)并默默地忽略欺骗。
总而言之,整个方案的重点是让您的服务器有机会设置欺骗标志 。 之后,根据需要丢弃(或处理)重复请求是您服务器的工作。 这一切都有意义吗?
我不能代表Android附带的HttpClient版本,因为它实际上是一个基于一个非常古老的BETA前快照的分支。 但是,如果您使用的是Apache HttpClient 4.x的库存版本,它不会自动重试POST或PUT请求,除非另有配置。
在您的特定情况下,我怀疑由于连接丢失或类似的网络问题,无线驱动程序会重新传输HTTP消息。 HTTP不是保证传递协议。 HTTP消息可以由较低级别的传输重新发送。 您的应用程序必须准备好处理重复的HTTP消息。
重试政策我们可以定制
与VOLLEY请求
stringRequest.setRetryPolicy(new DefaultRetryPolicy(0,DefaultRetryPolicy.DEFAULT_MAX_RETRIES,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)); volleySingleton.addToRequestQueue(stringRequest);