springboot2猪呢RestTemplate集成okhttp3并解决访问https报错问题

配置环境所使用的相关依赖

      
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.7.13</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <groupId>com.gmm</groupId>
   <artifactId>rest-template-okhttp3</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>rest-template-okhttp3</name>
   <description>Demo project for Spring Boot</description>
   <properties>
      <java.version>1.8</java.version>
   </properties>


   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>

      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <version>1.18.12</version>
      </dependency>

      <!-- okhttp -->
      <dependency>
         <groupId>com.squareup.okhttp3</groupId>
         <artifactId>okhttp</artifactId>
      </dependency>

      <dependency>
         <groupId>com.alibaba.fastjson2</groupId>
         <artifactId>fastjson2</artifactId>
         <version>2.0.27</version>
      </dependency>

      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-web</artifactId>
<!--         <version>6.0.10</version>-->
         <version>5.3.28</version>
      </dependency>

   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

</project>

 接下来配置RestTemplate,我们使用okhttp作为http请求连接工厂

private static SSLContext getSslContext(TrustManager[] trustAllCerts) throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        return sc;
    }

    private static X509TrustManager getTrustManager() {
        X509TrustManager x509TrustManager = new X509TrustManager() {
            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[]{};
            }


            @Override
            public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            }

            @Override
            public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            }
        };
        return x509TrustManager;
    }


    @Bean
    public RestTemplate restTemplate() throws NoSuchAlgorithmException, KeyManagementException {
        X509TrustManager x509TrustManager = getTrustManager();
        TrustManager[] trustAllCerts = new TrustManager[] { x509TrustManager };
        SSLContext sc = getSslContext(trustAllCerts);

        // SSL证书设置
        SSLSocketFactory socketFactory = sc.getSocketFactory();
        OkHttpClient.Builder bd = new okhttp3.OkHttpClient.Builder();
        bd.sslSocketFactory(socketFactory, x509TrustManager);

        // http连接工厂设置
        OkHttp3ClientHttpRequestFactory okHttp3ClientHttpRequestFactory = new OkHttp3ClientHttpRequestFactory(bd.build());
        okHttp3ClientHttpRequestFactory.setConnectTimeout(5000);
        okHttp3ClientHttpRequestFactory.setReadTimeout(8000);
        okHttp3ClientHttpRequestFactory.setWriteTimeout(8000);

        RestTemplate restTemplate = new RestTemplate(okHttp3ClientHttpRequestFactory);
        // 添加拦截器
        List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
        MyRequestInterceptor myRequestInterceptor = new MyRequestInterceptor();
        interceptors.add(myRequestInterceptor);
        restTemplate.setInterceptors(interceptors);
        // 中文乱码,主要是 StringHttpMessageConverter的默认编码为ISO导致的
        List<HttpMessageConverter<?>> list = restTemplate.getMessageConverters();
        for (HttpMessageConverter converter : list) {
            if (converter instanceof StringHttpMessageConverter) {
                ((StringHttpMessageConverter) converter).setDefaultCharset(StandardCharsets.UTF_8);
                break;
            }
        }

        return restTemplate;
    }
@Slf4j
public class MyRequestInterceptor implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] body, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
        //记录请求开始时间
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        //执行请求
        ClientHttpResponse response = clientHttpRequestExecution.execute(httpRequest, body);
        //执行完毕后,这里要创建备份,要不然会报io提前关闭的异常错误
        ClientHttpResponse responseCopy = new BufferingClientHttpResponseWrapper(response);
        //记录请求结束时间
        stopWatch.stop();
        //获取响应内容
        StringBuilder resBody = new StringBuilder();
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(responseCopy.getBody(), Charset.forName("UTF-8")))) {
            String line = bufferedReader.readLine();
            while (line != null) {
                resBody.append(line);
                line = bufferedReader.readLine();
            }
        }

        //获取请求内容
        String reqBody = "";
        //这里可以自定义想打印什么方法或者请求的内容,如下只打印post请求的日志,因为这时候才会带上body
        if (httpRequest.getHeaders().getContentType() != null && "POST".equals(httpRequest.getMethod().name())) {
            String requestBody = new String(body, Charset.forName("UTF-8"));
//                String contentType = httpRequest.getHeaders().getContentType().toString();
            //这里可以对contentType做一些判断,针对其格式化请求体的内容,如"application/x-www-form-urlencoded"格式会附带一些boundary(分割线)的内容
            reqBody = requestBody;

        }

        //打印日志的格式可以自定义
        log.info(JSON.toJSONString(RestLog.builder().costTime(stopWatch.getLastTaskTimeMillis()).headers(httpRequest.getHeaders()).method(httpRequest.getMethodValue())
                .reqUrl(httpRequest.getURI().toString()).reqBody(reqBody).resBody(resBody.toString()).resStatus(responseCopy.getRawStatusCode()).build()));

        return responseCopy;
    }

    /**
     * 响应内容备份
     */
    final class BufferingClientHttpResponseWrapper implements ClientHttpResponse {

        private final ClientHttpResponse response;

        private byte[] body;


        BufferingClientHttpResponseWrapper(ClientHttpResponse response) {
            this.response = response;
        }


        @Override
        public HttpStatus getStatusCode() throws IOException {
            return this.response.getStatusCode();
        }

        @Override
        public int getRawStatusCode() throws IOException {
            return this.response.getRawStatusCode();
        }

        @Override
        public String getStatusText() throws IOException {
            return this.response.getStatusText();
        }

        @Override
        public HttpHeaders getHeaders() {
            return this.response.getHeaders();
        }

        @Override
        public InputStream getBody() throws IOException {
            if (this.body == null) {
                this.body = StreamUtils.copyToByteArray(this.response.getBody());
            }
            return new ByteArrayInputStream(this.body);
        }

        @Override
        public void close() {
            this.response.close();
        }
    }

    /**
     * 定义日志的字段
     */
    @Data
    @Builder
    private static class RestLog {
        private String reqUrl;
        private String method;
        private HttpHeaders headers;
        private String reqBody;
        private String resBody;
        private long costTime;
        private int resStatus;
    }
}

相关测试

@Resource
private RestTemplate restTemplate;

@Test
public void httpGetTest2() {
	String url = "https://www.baidu.com";
	ResponseEntity<String> htmlEntity = restTemplate.getForEntity(url, String.class);

	HttpStatus status = htmlEntity.getStatusCode();
	System.out.println("返回http状态码 ==>> " + status.value());
	System.out.println("返回http状态码 ==>> " + htmlEntity.getStatusCode());
	System.out.println("返回http状态码 ==>> " + htmlEntity.getStatusCodeValue());

	HttpHeaders headers = htmlEntity.getHeaders();
	System.out.println(headers.toString());

	String htmlBody = htmlEntity.getBody();
	System.out.println("htmlBody === >> \n" + htmlBody);

	String htmlString = restTemplate.getForObject(url, String.class);
	System.out.println("htmlString === >>> \n" + htmlString);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值