OKHTTP解析之RetryAndFollowUpInterceptor重试机制,BAT大厂面试基础题集合

  1. 第二层判断如果请求已经开始,且当前请求最多只能被发送一次的情况下,则不允许重试;
  2. 判断当前请求是否可恢复的,以下异常场景不可恢复:
    a. ProtocolException,协议异常
    b. SocketTimeoutException,Socket链接超时且请求没有开始
    c. SSLHandshakeException && CertificateException :
    表示和服务端约定的安全级别不匹配异常,引起基本为证书引起的,这种链接是不可用的。
    d. SSLPeerUnverifiedException
    对等实体认证异常,也就是说对等个体没有被验证,类似没有证书,
    或者在握手期间没有建立对等个体验证;
  3. 判断是否存在其他可重试的路由,如果不存在,不允许重试;
  4. 不属于上述情况判断可以重试;
4. 发生IOException异常,是否可恢复判断逻辑参照上述RouteException判断逻辑;
5. 根据上一个Response结果构建一个新的response对象,且这个对象的body为空;
6. 根据请求码创建一个新的请求,以供下一次重试请求使用:会根据上一次的请求结果添加认证头信息,跟踪重定向或处理客户端请求超时等。

代码如下:

private Request followUpRequest(Response userResponse, @Nullable Route route) throws IOException {
if (userResponse == null) throw new IllegalStateException();
int responseCode = userResponse.code();

final String method = userResponse.request().method();
switch (responseCode) {
case HTTP_PROXY_AUTH:
Proxy selectedProxy = route != null
? route.proxy()
: client.proxy();
if (selectedProxy.type() != Proxy.Type.HTTP) {
throw new ProtocolException(“Received HTTP_PROXY_AUTH (407) code while not using proxy”);
}
return client.proxyAuthenticator().authenticate(route, userResponse);

case HTTP_UNAUTHORIZED:
return client.authenticator().authenticate(route, userResponse);

case HTTP_PERM_REDIRECT:
case HTTP_TEMP_REDIRECT:
// “If the 307 or 308 status code is received in response to a request other than GET
// or HEAD, the user agent MUST NOT automatically redirect the request”
if (!method.equals(“GET”) && !method.equals(“HEAD”)) {
return null;
}
// fall-through
case HTTP_MULT_CHOICE:
case HTTP_MOVED_PERM:
case HTTP_MOVED_TEMP:
case HTTP_SEE_OTHER:
// Does the client allow redirects?
if (!client.followRedirects()) return null;

String location = userResponse.header(“Location”);
if (location == null) return null;
HttpUrl url = userResponse.request().url().resolve(location);

// Don’t follow redirects to unsupported protocols.
if (url == null) return null;

// If configured, don’t follow redirects between SSL and non-SSL.
boolean sameScheme = url.scheme().equals(userResponse.request().url().scheme());
if (!sameScheme && !client.followSslRedirects()) return null;

// Most redirects don’t include a request body.
Request.Builder requestBuilder = userResponse.request().newBuilder();
if (HttpMethod.permitsRequestBody(method)) {
final boolean maintainBody = HttpMethod.redirectsWithBody(method);
if (HttpMethod.redirectsToGet(method)) {
requestBuilder.method(“GET”, null);
} else {
RequestBody requestBody = maintainBody ? userResponse.request().body() : null;
requestBuilder.method(method, requestBody);
}
if (!maintainBody) {
requestBuilder.removeHeader(“Transfer-Encoding”);
requestBuilder.removeHeader(“Content-Length”);
requestBuilder.removeHeader(“Content-Type”);
}
}

// When redirecting across hosts, drop all authentication headers. This
// is potentially annoying to the application layer since they have no
// way to retain them.
if (!sameConnection(userResponse.request().url(), url)) {
requestBuilder.removeHeader(“Authorization”);
}

return requestBuilder.url(url).build();

case HTTP_CLIENT_TIMEOUT:
// 408’s are rare in practice, but some servers like HAProxy use this response code. The
// spec says that we may repeat the request without modifications. Modern browsers also
// repeat the request (even non-idempotent ones.)
if (!client.retryOnConnectionFailure()) {
// The application layer has directed us not to retry the request.
return null;
}

RequestBody requestBody = userResponse.request().body();
if (requestBody != null && requestBody.isOneShot()) {
return null;
}

if (userResponse.priorResponse() != null
&& userResponse.priorResponse().code() == HTTP_CLIENT_TIMEOUT) {
// We attempted to retry and got another timeout. Give up.
return null;
}

if (retryAfter(userResponse, 0) > 0) {
return null;
}

return userResponse.request();

case HTTP_UNAVAILABLE:
if (userResponse.priorResponse() != null
&& userResponse.priorResponse().code() == HTTP_UNAVAILABLE) {
// We attempted to retry and got another timeout. Give up.
return null;
}

if (retryAfter(userResponse, Integer.MAX_VALUE) == 0) {
// specifically received an instruction to retry without delay
return userResponse.request();
}

return null;

default:
return null;
}
}

会根据结果码返回不同的Request对象(返回空表示当前的请求跟踪是没有必要的,或者可应用的):

  1. HTTP_PROXY_AUTH(407):代理认证,需要进行代理认证(默认实现返回null,可以进行重写覆盖实现);

  2. HTTP_UNAUTHORIZED(401):未授权,需要进行授权认证(默认实现返回null,可以进行重写覆盖实现);

  3. HTTP_PERM_REDIRECT(307) 或者 HTTP_TEMP_REDIRECT(308) :临时重定向或者永久重定向,如果请求方法不为GET且不为METHOD,返回空,表示不允许重定向;

  4. HTTP_MULT_CHOICE(300) 多选项
    HTTP_MOVED_PERM(301) 永久重定向,表示请求的资源已经分配了新的URI,以后应该使用新的URI
    HTTP_MOVED_TEMP(302)临时性重定向,
    HTTP_MOVED_TEMP(303)表示由于请求对应的资源存在着另外一个URI,应该使用GET方法定向获取请求的资源

这四种code对应的逻辑为:

  1. 首先判断是否允许重定向,不允许返回空;

  2. 然后判断结果里面locations头,是否可以解析,不可正常解析返回空;

  3. 结果返回scheme和请求的scheme不一致且不允许ssl重定向,返会空;

  4. 针对存在请求body的,如果可以重定向为GET,则构建GET请求,否则构建原有请求;

  5. 跨主机重定向时,删除所有身份验证头。

  6. 最后构建请求Request对象。

  7. HTTP_CLIENT_TIMEOUT(408):请求超时,逻辑如下

  8. 如果不允许重试,直接返回空

  9. 如果当前Response不为空,且只允许请求一次,则直接返回空

  10. 本次请求结果和上一次请求结果均超时,则放弃重试

  11. 解析结果相应头Retry-After(响应的 HTTP 报头指示所述用户代理应该多长时间使一个后续请求之前等待): 如果当前Retry-After大于0,则返回空;

  12. HTTP_UNAVAILABLE(503):表明服务器暂时处于超负载或正在进行停机维护,现无法处理请求。

  13. 本次请求结果和上一次请求结果均返回503,则放弃重试

  14. 如果返回的Retry-After为0,没有任何延迟,则返回Request对象,否则返回空;

7. 如果第六步构建的出来的Request为空,则不再进行,直接返回Response
8. 构建的Request对象出存在请求body且为一次性请求,则直接返回Response,也不进行重试。
9. 最后判断当前重试次数是否已经到达最大次数(默认20),如果到达,则直接抛出异常。
10. 如果上述没有抛出异常或者中断循环,则进入while循环,开始下一次重试过程。

到此,重试机制RetryAndFollowUpInterceptor 分析结束。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

结尾

我还总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料,免费分享给大家。
(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。

领取方式:关注+点赞+点击我的GitHub 免费获取

a在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。**

领取方式:关注+点赞+点击我的GitHub 免费获取

image

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对你的问,我可以给出以下的基于 OkHttp重试拦截器实现: ```java public class RetryInterceptor implements Interceptor { private final int maxRetryCount; private final long retryInterval; public RetryInterceptor(int maxRetryCount, long retryInterval) { this.maxRetryCount = maxRetryCount; this.retryInterval = retryInterval; } @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = null; IOException exception = null; int tryCount = 0; while (tryCount <= maxRetryCount) { try { response = chain.proceed(request); if (response.isSuccessful()) { return response; } } catch (IOException e) { exception = e; } tryCount++; if (tryCount <= maxRetryCount) { try { Thread.sleep(retryInterval); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } } } if (exception != null) { throw exception; } throw new IOException("Request failed after " + maxRetryCount + " attempts."); } } ``` 在这个拦截器中,我们可以通过传入最大重试次数和重试间隔时间来配置拦截器。当请求失败时,会在一定时间后重新尝试请求,直到达到最大重试次数或请求成功为止。如果最大重试次数用完后仍然失败,则抛出异常。 使用这个拦截器需要在 OkHttpClient 中添加: ```java OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new RetryInterceptor(3, 1000)) .build(); ``` 这样就可以在 OkHttp 的请求中添加重试功能了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值