okHttp 重试

本贴最后更新于 1688 天前,其中的信息可能已经物是人非
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 回帖 • 56 关注

相关帖子

回帖

欢迎来到这里!

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

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

推荐标签 标签

  • 开源

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

    393 引用 • 3380 回帖 • 1 关注
  • Ubuntu

    Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的 Linux 操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu”一词,意思是“人性”、“我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的“仁爱”思想。Ubuntu 的目标在于为一般用户提供一个最新的、同时又相当稳定的主要由自由软件构建而成的操作系统。

    123 引用 • 168 回帖
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    198 引用 • 120 回帖
  • BND

    BND(Baidu Netdisk Downloader)是一款图形界面的百度网盘不限速下载器,支持 Windows、Linux 和 Mac,详细介绍请看这里

    107 引用 • 1281 回帖 • 22 关注
  • 电影

    这是一个不能说的秘密。

    120 引用 • 597 回帖
  • Dubbo

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

    60 引用 • 82 回帖 • 590 关注
  • Swagger

    Swagger 是一款非常流行的 API 开发工具,它遵循 OpenAPI Specification(这是一种通用的、和编程语言无关的 API 描述规范)。Swagger 贯穿整个 API 生命周期,如 API 的设计、编写文档、测试和部署。

    26 引用 • 35 回帖 • 7 关注
  • 博客

    记录并分享人生的经历。

    270 引用 • 2386 回帖
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    185 引用 • 318 回帖 • 352 关注
  • SQLServer

    SQL Server 是由 [微软] 开发和推广的关系数据库管理系统(DBMS),它最初是由 微软、Sybase 和 Ashton-Tate 三家公司共同开发的,并于 1988 年推出了第一个 OS/2 版本。

    19 引用 • 31 回帖
  • 心情

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

    59 引用 • 369 回帖
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 380 关注
  • WordPress

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

    45 引用 • 113 回帖 • 321 关注
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    491 引用 • 1383 回帖 • 370 关注
  • 以太坊

    以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约、开源的底层系统。以太坊是一个平台和一种编程语言 Solidity,使开发人员能够建立和发布下一代去中心化应用。 以太坊可以用来编程、分散、担保和交易任何事物:投票、域名、金融交易所、众筹、公司管理、合同和知识产权等等。

    34 引用 • 367 回帖 • 2 关注
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    84 引用 • 139 回帖
  • JWT

    JWT(JSON Web Token)是一种用于双方之间传递信息的简洁的、安全的表述性声明规范。JWT 作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以 JSON 的形式安全的传递信息。

    20 引用 • 15 回帖 • 18 关注
  • Sillot

    Sillot (汐洛)孵化自思源笔记,致力于服务智慧新彖乄,具有彖乄驱动、极致优雅、开发者友好的特点
    Github 地址:https://github.com/Hi-Windom/Sillot

    12 引用 • 26 关注
  • Log4j

    Log4j 是 Apache 开源的一款使用广泛的 Java 日志组件。

    20 引用 • 18 回帖 • 36 关注
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    89 引用 • 113 回帖
  • Scala

    Scala 是一门多范式的编程语言,集成面向对象编程和函数式编程的各种特性。

    13 引用 • 11 回帖 • 101 关注
  • 导航

    各种网址链接、内容导航。

    37 引用 • 168 回帖
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 444 关注
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 674 关注
  • Gzip

    gzip (GNU zip)是 GNU 自由软件的文件压缩程序。我们在 Linux 中经常会用到后缀为 .gz 的文件,它们就是 Gzip 格式的。现今已经成为互联网上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

    9 引用 • 12 回帖 • 106 关注
  • OAuth

    OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 oAuth 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 oAuth 是安全的。oAuth 是 Open Authorization 的简写。

    36 引用 • 103 回帖 • 6 关注
  • InfluxDB

    InfluxDB 是一个开源的没有外部依赖的时间序列数据库。适用于记录度量,事件及实时分析。

    2 引用 • 47 关注