okHttp 重试

本贴最后更新于 1777 天前,其中的信息可能已经物是人非
package club.wujingjian.util;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import okhttp3.ConnectionPool;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient.Builder;
import org.springframework.http.*;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.ClassUtils;
import org.springframework.web.client.RestTemplate;

@Slf4j
public class OKHttpUtil {

    private static final boolean jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper",
            RestTemplate.class.getClassLoader())
            && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", RestTemplate.class.getClassLoader());

    private static final boolean springwebPresent = ClassUtils.isPresent(
            "org.springframework.http.converter.json.Jackson2ObjectMapperBuilder", RestTemplate.class.getClassLoader());


    private int readTimeout = 2000;
    private int connectTimeout=1000;
    private boolean isRetry = true;
    private int retryCount = 3;
    private long retryDelay = 100;


    public okhttp3.OkHttpClient okHttpClient() {
        Builder builder = new Builder();
        ConnectionPool pool = new ConnectionPool(1000, 50, TimeUnit.MINUTES);
        builder.connectionPool(pool);
        builder.retryOnConnectionFailure(isRetry);
//        RetryInterceptor retryIntercepter = new RetryInterceptor(retryCount, retryDelay,new ArrayList<>());
        RetryInterceptor retryIntercepter = new RetryInterceptor(retryCount, retryDelay);
        builder.addInterceptor(retryIntercepter);
        builder.followRedirects(false);
        return builder.build();
    }

    public RestTemplate restClientOnlyTemplateSimple() {

        OkHttp3ClientHttpRequestFactory okHttp3ClientHttpRequestFactory = new OkHttp3ClientHttpRequestFactory(
                okHttpClient());
        okHttp3ClientHttpRequestFactory.setReadTimeout(readTimeout);
        okHttp3ClientHttpRequestFactory.setConnectTimeout(connectTimeout);
        RestTemplate restTemplate = new RestTemplate(okHttp3ClientHttpRequestFactory);

        // 使用 utf-8 编码集的 convert 替换默认的 convert(默认的 string conver 的编码集为
        // "ISO-8859-1")
        List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
        Iterator<HttpMessageConverter<?>> iterator = messageConverters.iterator();
        while (iterator.hasNext()) {
            HttpMessageConverter<?> converter = iterator.next();
            if (converter instanceof StringHttpMessageConverter) {
                iterator.remove();
            }
            if (converter instanceof MappingJackson2HttpMessageConverter) {
                iterator.remove();
            }
        }

        StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(
                Charset.forName("UTF-8"));
        stringHttpMessageConverter.setWriteAcceptCharset(false);
        List<MediaType> mediaTypeList = new ArrayList<>();
        mediaTypeList.add(MediaType.APPLICATION_JSON_UTF8);
        mediaTypeList.add(MediaType.APPLICATION_FORM_URLENCODED);
        mediaTypeList.add(MediaType.APPLICATION_JSON);
        mediaTypeList.add(MediaType.TEXT_PLAIN);
        mediaTypeList.add(MediaType.TEXT_HTML);
        mediaTypeList.add(new MediaType("text", "json"));
        mediaTypeList.add(new MediaType("text", "javascript"));
        stringHttpMessageConverter.setSupportedMediaTypes(mediaTypeList);
        messageConverters.add(0, stringHttpMessageConverter);

        // 兼容JSON与实体字段不对应
        if (jackson2Present && springwebPresent) {
            ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(objectMapper);
            messageConverters.add(jsonConverter);
        }

        return restTemplate;
    }


    public static void main(String[] args) {
        OKHttpUtil okHttpUtil = new OKHttpUtil();
        RestTemplate restTemplate = okHttpUtil.restClientOnlyTemplateSimple();
        String url ="http://mobileself-xxx.ffff.beta/api/v2/staffinfo/exist/xxx";
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json;charset=UTF-8");
        headers.setContentType(type);
        headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
        headers.set("xiaofanAuthorization","aaa#aaa");
        HttpEntity<?> entity = new HttpEntity<>(headers);
        try {
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
            if (null != response) {
                System.out.println("响应数据:" + response.getBody());
            }
        } catch (Exception e) {
            log.error("请求小凡接口异常:"+e.getMessage(),e);
        }

    }
}

package club.wujingjian.util;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.ConnectException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.net.ssl.SSLException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.collections.CollectionUtils;
import org.apache.http.conn.HttpHostConnectException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class RetryInterceptor implements Interceptor {
    private static Logger logger = LoggerFactory.getLogger(RetryInterceptor.class);
    private final int retryCount;
    private final long retryDelay;
    private final Set<Class<? extends IOException>> nonRetriableClasses;//不会重试的类型
    private static final Charset UTF8 = Charset.forName("UTF-8");

    protected RetryInterceptor(int retryCount, long retryDelay, Collection<Class<? extends IOException>> clazzes) {
        this.retryCount = retryCount;
        this.retryDelay = retryDelay;
        this.nonRetriableClasses = new HashSet();
        if (CollectionUtils.isNotEmpty(clazzes)) {
            Iterator noRetryIterator = clazzes.iterator();

            while(noRetryIterator.hasNext()) {
                Class<? extends IOException> clazz = (Class)noRetryIterator.next();
                this.nonRetriableClasses.add(clazz);
            }
        }

    }

    public RetryInterceptor(int retryCount, long retryDelay) {
        this(retryCount, retryDelay, Arrays.asList(InterruptedIOException.class, UnknownHostException.class, SSLException.class, HttpHostConnectException.class,ConnectException.class));
    }

    public RetryInterceptor() {
        this(3, 50L);
    }

    public Response intercept(Chain chain) throws IOException {
        Response response = null;
        try {
            Request request = chain.request();
            for (int execCount = 0; execCount <= retryCount; execCount++) {
                if (execCount >= 1) {
                    logger.info("重试第{}次,url:{}", execCount, request.url().url());
                }
                try {
                    Exception exception;
                    Iterator varException;
                    try {
                        response = chain.proceed(request);
                        break;
                    } catch (Exception ex) {
                        exception = ex;
                        if (execCount >= this.retryCount) {
                            throw ex;
                        }
                        if (this.nonRetriableClasses.contains(ex.getClass())) {
                            throw ex;
                        }
                        varException = this.nonRetriableClasses.iterator();
                    }

                    while (varException.hasNext()) {
                        Class<? extends IOException> rejectException = (Class) varException.next();
                        if (rejectException.isInstance(exception)) {
                            throw exception;
                        }
                    }

                    try {
                        Thread.sleep(this.retryDelay);
                    } catch (InterruptedException interruptedException) {
                        logger.error("重试错误:" + interruptedException.getMessage(), interruptedException);
                    }
                } finally {
                    if (execCount >= 1) {
                        logger.info("重试{}次结束,url:{}", execCount, request.url().url());
                    }

                }
            }

        } catch (Exception e) {
            logger.error("请求错误了:"+e.getMessage(),e);
        }
        return response;
    }


}


  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 47 关注

相关帖子

回帖

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 前端

    前端技术一般分为前端设计和前端开发,前端设计可以理解为网站的视觉设计,前端开发则是网站的前台代码实现,包括 HTML、CSS 以及 JavaScript 等。

    247 引用 • 1347 回帖 • 1 关注
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 434 关注
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    76 引用 • 37 回帖
  • frp

    frp 是一个可用于内网穿透的高性能的反向代理应用,支持 TCP、UDP、 HTTP 和 HTTPS 协议。

    16 引用 • 7 回帖 • 1 关注
  • 倾城之链
    23 引用 • 66 回帖 • 120 关注
  • CSS

    CSS(Cascading Style Sheet)“层叠样式表”是用于控制网页样式并允许将样式信息与网页内容分离的一种标记性语言。

    184 引用 • 461 回帖
  • 开源

    Open Source, Open Mind, Open Sight, Open Future!

    402 引用 • 3507 回帖
  • IDEA

    IDEA 全称 IntelliJ IDEA,是一款 Java 语言开发的集成环境,在业界被公认为最好的 Java 开发工具之一。IDEA 是 JetBrains 公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。

    180 引用 • 400 回帖
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    163 引用 • 473 回帖
  • 小薇

    小薇是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动。

    由于 Smart QQ 从 2019 年 1 月 1 日起停止服务,所以该项目也已经停止维护了!

    34 引用 • 467 回帖 • 708 关注
  • 负能量

    上帝为你关上了一扇门,然后就去睡觉了....努力不一定能成功,但不努力一定很轻松 (° ー °〃)

    87 引用 • 1206 回帖 • 452 关注
  • Mac

    Mac 是苹果公司自 1984 年起以“Macintosh”开始开发的个人消费型计算机,如:iMac、Mac mini、Macbook Air、Macbook Pro、Macbook、Mac Pro 等计算机。

    164 引用 • 594 回帖 • 1 关注
  • Dubbo

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是 [阿里巴巴] SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

    60 引用 • 82 回帖 • 612 关注
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 642 关注
  • App

    App(应用程序,Application 的缩写)一般指手机软件。

    90 引用 • 383 回帖 • 1 关注
  • RESTful

    一种软件架构设计风格而不是标准,提供了一组设计原则和约束条件,主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

    30 引用 • 114 回帖
  • gRpc
    10 引用 • 8 回帖 • 58 关注
  • V2EX

    V2EX 是创意工作者们的社区。这里目前汇聚了超过 400,000 名主要来自互联网行业、游戏行业和媒体行业的创意工作者。V2EX 希望能够成为创意工作者们的生活和事业的一部分。

    17 引用 • 236 回帖 • 395 关注
  • 生活

    生活是指人类生存过程中的各项活动的总和,范畴较广,一般指为幸福的意义而存在。生活实际上是对人生的一种诠释。生活包括人类在社会中与自己息息相关的日常活动和心理影射。

    229 引用 • 1450 回帖
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖 • 1 关注
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖 • 1 关注
  • 七牛云

    七牛云是国内领先的企业级公有云服务商,致力于打造以数据为核心的场景化 PaaS 服务。围绕富媒体场景,七牛先后推出了对象存储,融合 CDN 加速,数据通用处理,内容反垃圾服务,以及直播云服务等。

    26 引用 • 222 回帖 • 171 关注
  • 博客

    记录并分享人生的经历。

    272 引用 • 2386 回帖
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    140 引用 • 3720 回帖
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    45 引用 • 113 回帖 • 287 关注
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    170 引用 • 414 回帖 • 406 关注
  • OpenResty

    OpenResty 是一个基于 NGINX 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

    17 引用 • 39 关注