欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring boot 使用RestTemplate信任所有https请求

程序员文章站 2022-07-10 15:24:14
...

RestTemplate在访问https资源时,出现报错
java.security.cert.CertificateException: No subject alternative names matching IP address ******* found; 

该问题主要是由于https请求时需要服务侧提供的证书认证,如果没有证书的话,可通过以下方法来信任请求:

一、通过CloseableHttpClient来信任所有https的请求(绕过证书认证)

import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class HttpClientUtils {

    /**
     * CloseableHttpClient 信任所有https请求
     *
     * @return
     * @throws KeyStoreException
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
    public static CloseableHttpClient acceptsUntrustedCertsHttpClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        HttpClientBuilder b = HttpClientBuilder.create();

        // 设置信任所有证书
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                return true;
            }
        }).build();
        b.setSSLContext(sslContext);

        HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;

        SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", sslSocketFactory)
                .build();

        PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        connMgr.setMaxTotal(200);
        connMgr.setDefaultMaxPerRoute(100);
        b.setConnectionManager(connMgr);

        CloseableHttpClient client = b.build();

        return client;
    }

}

二、 配置RestTemplate实例

import com.eastcom.intsight.fault.intellect.collect.util.HttpClientUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean(name = "restTemplate")
    public RestTemplate httpsRestTemplate(HttpComponentsClientHttpRequestFactory httpsFactory){
        RestTemplate restTemplate = new RestTemplate(httpsFactory);
        restTemplate.setErrorHandler(new ResponseErrorHandler() {
            @Override
            public boolean hasError(ClientHttpResponse clientHttpResponse) {
                return false;
            }

            @Override
            public void handleError(ClientHttpResponse clientHttpResponse) {
                //默认处理非200的返回,会抛异常
            }
        });
        return restTemplate;
    }

    @Bean(name = "httpsFactory")
    public HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory() throws Exception{
        CloseableHttpClient httpClient = HttpClientUtils.acceptsUntrustedCertsHttpClient();
        HttpComponentsClientHttpRequestFactory httpsFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        httpsFactory.setReadTimeout(2000);
        httpsFactory.setConnectTimeout(2000);
        return httpsFactory;
    }

}

三、 附上自己封装的RestTemplate工具类

import com.*.enums.BizExceptionCodeEnum;
import com.*.enums.ResultCodeEnum;
import com.*.exception.BizException;
import com.*.model.Result;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.Map;

@Service
@Slf4j
public class InvokingService {

    @Resource(name = "restTemplate")
    private RestTemplate restTemplate;

    /**
     * 服务调用,返回响应Body
     *
     * @param url
     * @param type
     * @param paramType 参数类型,若是post请求,且参数类型为'@RequestBody'时,需特殊处理
     * @param headerMap 参数类型,若是post请求,且参数类型为'@RequestBody'时,需特殊处理
     * @param paramMap  参数类型为'@RequestBody'时,参数Map中只放一个随意key即可,值为JSON字符串参数
     * @return
     */
    public String invServiceForResultData(String url, String type, String paramType, Map<String, String> headerMap, Map<String, String> paramMap) {
        try {
            String resultObj = "";
            HttpEntity requestEntity = buildRequestEntity(paramType, headerMap, paramMap);
            if ("GET".equalsIgnoreCase(type)) {
                resultObj = restTemplate.getForObject(url, String.class);
            } else if ("POST".equalsIgnoreCase(type)) {
                resultObj = restTemplate.postForObject(url, requestEntity, String.class);
            } else if ("PUT".equalsIgnoreCase(type) || "DELETE".equalsIgnoreCase(type)) {
                ResponseEntity<String> responseEntity = restTemplate.exchange(url, choiceHttpMethod(type), requestEntity, String.class);
                resultObj = responseEntity.getBody();
            }
            return resultObj;
        } catch (Exception e) {
            JSONObject errorObj = new JSONObject();
            errorObj.put("url", url);
            errorObj.put("type", type);
            Result result = new Result(ResultCodeEnum.C505, errorObj);
            return JSONObject.fromObject(result).toString();
        }
    }

    /**
     * 服务调用,返回响应体,可获取所有响应信息,如响应头,响应code等
     *
     * @param url
     * @param type
     * @param paramType
     * @param headerMap
     * @param paramMap
     * @return
     */
    public ResponseEntity<String> invServiceForResultEntity(String url, String type, String paramType, Map<String, String> headerMap, Map<String, String> paramMap) {
        try {
            ResponseEntity<String> responseEntity = null;
            HttpEntity requestEntity = buildRequestEntity(paramType, headerMap, paramMap);
            responseEntity = restTemplate.exchange(url, choiceHttpMethod(type), requestEntity, String.class);
            return responseEntity;
        } catch (Exception e) {
            e.printStackTrace();
            JSONObject errorObj = new JSONObject();
            errorObj.put("url", url);
            errorObj.put("type", type);
            throw new BizException(BizExceptionCodeEnum.INVOKING_ERROR, errorObj.toString());
        }
    }

    /**
     * 构建http请求配置
     *
     * @param paramType
     * @param headerMap
     * @param paramMap
     * @return
     */
    public HttpEntity buildRequestEntity(String paramType, Map<String, String> headerMap, Map<String, String> paramMap) {
        HttpEntity requestEntity = null;
        HttpHeaders headers = setHeaders(headerMap);
        if ("BODY".equalsIgnoreCase(paramType)) {
            headers.setContentType(MediaType.valueOf("application/json;UTF-8"));
            String param = "";
            if (null != paramMap) {
                for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                    param = entry.getValue();
                    break;
                }
            }
            requestEntity = new HttpEntity(JSONObject.fromObject(param), headers);
        } else {
            MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
            if (null != paramMap) {
                for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                    params.add(entry.getKey(), entry.getValue());
                }
            }
            requestEntity = new HttpEntity(params, headers);
        }
        return requestEntity;
    }

    /**
     * 设置请求头部信息
     *
     * @param headerMap
     * @return
     */
    public HttpHeaders setHeaders(Map<String, String> headerMap) {
        HttpHeaders headers = new HttpHeaders();
        if (null == headerMap) {
            return headers;
        }
        for (Map.Entry<String, String> entry : headerMap.entrySet()) {
            headers.set(entry.getKey(), entry.getValue());
        }
        return headers;
    }

    /**
     * 选择请求方式
     *
     * @param type
     * @return
     */
    public HttpMethod choiceHttpMethod(String type) {
        if ("GET".equalsIgnoreCase(type)) {
            return HttpMethod.GET;
        } else if ("POST".equalsIgnoreCase(type)) {
            return HttpMethod.POST;
        } else if ("PUT".equalsIgnoreCase(type)) {
            return HttpMethod.PUT;
        } else if ("DELETE".equalsIgnoreCase(type)) {
            return HttpMethod.DELETE;
        } else if ("HEAD".equalsIgnoreCase(type)) {
            return HttpMethod.HEAD;
        } else if ("PATCH".equalsIgnoreCase(type)) {
            return HttpMethod.PATCH;
        } else if ("OPTIONS".equalsIgnoreCase(type)) {
            return HttpMethod.OPTIONS;
        } else if ("TRACE".equalsIgnoreCase(type)) {
            return HttpMethod.TRACE;
        } else {
            return HttpMethod.POST;
        }
    }

}