java 重试 http 连接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3929748/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 04:00:17  来源:igfitidea点击:

Retrying an http connection

javaandroid

提问by user291701

I'm making an http request. I'm on a platform (android) where network operations often fail because the network connection might not be immediately available. Therefore I'd like to try the same connection N times before completely failing. Was thinking of something like this:

我正在发出一个 http 请求。我在一个平台 (android) 上,网络操作经常失败,因为网络连接可能无法立即可用。因此,我想在完全失败之前尝试 N 次相同的连接。一直在想这样的事情:

DefaultHttpClient mHttp = ...;

public HttpResponse runHttpRequest(HttpRequestBase httpRequest) 
    throws IOException
{
    IOException last = null;
    for (int attempt = 0; attempt < 3; attempt++) {
        try {
            HttpResponse response = mHttpClient.execute(httpRequest);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                return response;
            }
        } catch (IOException e) {
            httpRequest.abort();
            last = e;
        }
    }

    throw last;
}

I'm mostly worried about the connection being in some state which is invalid on subsequent retries. In other words, do I need to completely recreate 'httpRequest', should I avoid calling httpRequest.abort() in the catch block, and only call it in the final failure?

我最担心的是连接处于某种状态,在随后的重试中无效。换句话说,我是否需要完全重新创建“httpRequest”,我是否应该避免在 catch 块中调用 httpRequest.abort(),而只在最终失败时调用它?

Thanks

谢谢

回答by Michael Aaron Safyan

The documentation does not mention that such a thing will occur, although you'd have to try it. More importantly, though, there are some things that you should consider with your code...

文档没有提到会发生这样的事情,尽管您必须尝试一下。但是,更重要的是,您应该在代码中考虑一些事情......

  1. You should probably expose the number of retries, allowing the caller to specify this value.
  2. You should only retry if an exception was thrown; you currently retry unless you get a 200. However if, for example, you get a 404... this doesn't mean your request failed in the sense that the network did not fail... rather, you made a successful round-trip to the server, but the server simply doesn't have the requested resource... so it really doesn't make sense to retry in such a case.
  3. As-is, you might suppress all sorts of different types of exceptions. It might make sense to record all the exceptions that occurred in a List and return some sort of result object which contains the response (possibly null if all attempts failed) in addition to a list of all exceptions. Otherwise, you throw some arbitrary exception from the set of exceptions that occurred, possibly obscuring failure.
  4. Right now you just hammer away with the same request, over and over again... if there is congestion, you are just adding to it. And if your IP address was banned for too much activity, you are probably going to be adding to that... any sort of retry logic should have a back-off behavior where there is some amount of waiting between retries and that interval increases with each failure.
  1. 您可能应该公开重试次数,允许调用者指定此值。
  2. 您应该只在抛出异常时重试;除非您得到 200,否则您目前会重试。但是,例如,如果您得到 404...这并不意味着您的请求失败,因为网络没有失败...相反,您进行了一次成功的回合-前往服务器,但服务器根本没有请求的资源......所以在这种情况下重试真的没有意义。
  3. 按原样,您可能会抑制各种不同类型的异常。记录列表中发生的所有异常并返回某种结果对象可能有意义,该对象包含响应(如果所有尝试都失败,则可能为 null)以及所有异常的列表。否则,您会从发生的异常集中抛出一些任意异常,可能会掩盖失败。
  4. 现在你只是一遍又一遍地重复相同的请求......如果有拥塞,你只是在增加它。如果您的 IP 地址因活动过多而被禁止,那么您可能会添加...每一次失败。

回答by BenV

A HttpRequestRetryHandlerseems like it might be helpful here.

A HttpRequestRetryHandler似乎在这里可能会有所帮助。

回答by yegor256

I'd recommend to use AOP and Java annotations from jcabi-aspects(I'm a developer):

我建议使用来自jcabi 方面的AOP 和 Java 注释(我是一名开发人员):

@RetryOnFailure(attempts = 3, delay = 5)
public String load(URL url) {
  return url.openConnection().getContent();
}