原创

Java-HttpClientUtil-RestTemplate-http请求工具-去掉ssl校验

### 1.HttpClientUtil.java
> 去掉SSL校验 CustomizedHostnameVerifier getHttpClientBuilder

```
 
package cn.jiangjiesheng.edu.utils;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import cn.jiangjiesheng.bootstrap.qpaas.properties.LegacyPaasProperties;
import cn.jiangjiesheng.edu.config.NacosConfig;
import cn.jiangjiesheng.edu.core.AyStatic;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* 〈一句话功能简述〉<br>
* 〈功能详细描述〉
*
* @author suntaiguo
* @version [版本号, 2018年5月18日]
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
@Component
@Slf4j
public class HttpClientUtil {
private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class); // 日志记录

private static RequestConfig requestConfig = null;

@Autowired
private LegacyPaasProperties paasConfig;
@Autowired
private HttpClientUtil self;
@Autowired
private NacosConfig nacosConfig;

@Value(value = "${isAutoGetCookieDomain:true}")
private Boolean isAutoGetCookieDomain;


@Value("#{'${domainNameList:}'.split(',')}")
private List<String> domainNameList;

static {
// 设置请求和传输超时时间
requestConfig = RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000).build();
}

/**
* post请求传输json参数
*
* @param url url地址
* 参数
* @return
*/
public static JSONObject httpPost(String url, JSONObject jsonParam) {
// post请求返回结果
CloseableHttpClient httpClient = getHttpClientBuilder().build();
JSONObject jsonResult = null;
HttpPost httpPost = new HttpPost(url);
// 设置请求和传输超时时间
httpPost.setConfig(requestConfig);
try {
if (null != jsonParam) {
// 解决中文乱码问题
StringEntity entity = new StringEntity(jsonParam.toString(), "utf-8");
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
}
CloseableHttpResponse result = httpClient.execute(httpPost);
// 请求发送成功,并得到响应
if (result.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String str = "";
try {
// 读取服务器返回过来的json字符串数据
str = EntityUtils.toString(result.getEntity(), "utf-8");
// 把json字符串转换成json对象
jsonResult = JSONObject.parseObject(str);
} catch (Exception e) {
logger.error("post请求提交失败:" + url, e);
}
}
} catch (IOException e) {
logger.error("post请求提交失败:" + url, e);
} finally {
httpPost.releaseConnection();
}
return jsonResult;
}

/**
* post请求传输String参数 例如:name=Jack&sex=1&type=2
* Content-type:application/x-www-form-urlencoded
*
* @param url url地址
* @param strParam 参数
* @return
*/
public static JSONObject httpPost(String url, String strParam, String code) {
// post请求返回结果
CloseableHttpClient httpClient = getHttpClientBuilder().build();
JSONObject jsonResult = null;
HttpPost httpPost = new HttpPost(url);
httpPost.setConfig(requestConfig);
try {
if (null != strParam) {
// 解决中文乱码问题
StringEntity entity = new StringEntity(strParam, "utf-8");
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
}
if (StrUtil.isNotEmpty(code)) {
httpPost.setHeader("code_str", code);
}
CloseableHttpResponse result = httpClient.execute(httpPost);
// 请求发送成功,并得到响应
if (result.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String str = "";
try {
// 读取服务器返回过来的json字符串数据
str = EntityUtils.toString(result.getEntity(), "utf-8");
// 把json字符串转换成json对象
jsonResult = JSONObject.parseObject(str);
} catch (Exception e) {
logger.error("post请求提交失败:" + url, e);
}
}
} catch (IOException e) {
logger.error("post请求提交失败:" + url, e);
} finally {
httpPost.releaseConnection();
}
return jsonResult;
}

/**
* 发送get请求
*
* @param url 路径
* @return
*/
public static JSONObject httpGet(String url, String sessionId) {
// get请求返回结果
JSONObject jsonResult = null;
CookieStore cookieStore = new BasicCookieStore();
CloseableHttpClient client = getHttpClientBuilder().setDefaultCookieStore(cookieStore).build();
// 发送get请求
HttpGet httpGet = new HttpGet(url);
httpGet.setConfig(requestConfig);
try {
//设置cookie
httpGet.setHeader("Cookie", "PHPSESSID=" + sessionId + "; Path=/; HttpOnly;");
CloseableHttpResponse response = client.execute(httpGet);
// 请求发送成功,并得到响应
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
// 读取服务器返回过来的json字符串数据
HttpEntity entity = response.getEntity();
String strResult = EntityUtils.toString(entity, "utf-8");
// 把json字符串转换成json对象
jsonResult = JSONObject.parseObject(strResult);
} else {
logger.error("get请求提交失败:" + url);
}
} catch (IOException e) {
logger.error("get请求提交失败:" + url, e);
} finally {
httpGet.releaseConnection();
}
return jsonResult;
}

public static void main(String[] args) {
String url ="http://baoxianjiance-shukechanpinkaifa-wrrcyk.k8s-assembly-machine.qpaas.com/api/professional/seats/forjava/GetExamPaperBaseDetail?containerId=kehufengxianfuwuxito&paperId=2";
byte[] bytes = new byte[0];
try {
bytes = onlineImage2byte(url);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(bytes);
String s = httpGetStr(url);
System.out.println(s);
}


public static String httpGetStr(String url) {
// get请求返回结果
String strResult = null;
CloseableHttpClient client = getHttpClientBuilder().build();
// 发送get请求
HttpGet request = new HttpGet(url);
logger.info("httpGetStr:url:{}", url);
request.setConfig(requestConfig);
try {
CloseableHttpResponse response = client.execute(request);

// 请求发送成功,并得到响应
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
// 读取服务器返回过来的json字符串数据
HttpEntity entity = response.getEntity();
strResult = EntityUtils.toString(entity, "utf-8");

} else {
logger.error("get请求提交失败:" + url);
}
} catch (IOException e) {
logger.error("get请求提交失败:" + url, e);
} finally {
request.releaseConnection();
}
return strResult;
}

//根据返回的string是XML格式还是json格式的文件,然后对该文件进行选择不同的处理方式
public static String postMethod(String url, Map<String, String> params, String jsonDataStr, String sessionId) throws Exception {

logger.info("postMethod,post请求入参:url:{},params:{},jsonDataStr:{},sessionId:{}", url, params, jsonDataStr, sessionId);
CookieStore cookieStore = new BasicCookieStore();
CloseableHttpClient client = getHttpClientBuilder().setDefaultCookieStore(cookieStore).build();
CloseableHttpResponse response = null;

RequestConfig config = RequestConfig.custom().setConnectTimeout(20000).setSocketTimeout(20000).build();
HttpPost httpPost = new HttpPost(url);
httpPost.setConfig(config);

try {
//设置cookie
//httpPost.setHeader("Cookie","PHPSESSID="+sessionId+"; Path=/; Domain=.szkj.demo.qpaas.com; HttpOnly;");
httpPost.setHeader("Cookie", "PHPSESSID=" + sessionId + "; Path=/; HttpOnly;");
if (StringUtils.isNotBlank(jsonDataStr)) {
httpPost.setEntity(new StringEntity(jsonDataStr, ContentType.APPLICATION_JSON));
} else if (params != null) {
List<NameValuePair> list = new ArrayList<NameValuePair>();
Set<String> keySets = params.keySet();
for (String key : keySets) {
String value = params.get(key);
list.add(new BasicNameValuePair(key, value));
}
httpPost.setEntity(new UrlEncodedFormEntity(list, HTTP.UTF_8));
}
response = client.execute(httpPost);
HttpEntity entity = response.getEntity();
String content = EntityUtils.toString(entity);
logger.info("postMethod,post请求结果:url:{},params:{},jsonDataStr:{},sessionId:{},content:{}", url, params, jsonDataStr, sessionId, content);
return content;
} catch (Exception e) {
logger.error("postMethod,post请求出现异常:url:{},params:{},jsonDataStr:{},sessionId:{}", url, params, jsonDataStr, sessionId, e);
throw e;
} finally {
httpPost.releaseConnection();
response.close();
}
}

/**
* 获取设置cookie的domain
* 注意:qpaas.com平台需要设置成 .qpaas.com ,保持和此平台的PHPSESSID一直,避免生产多个PHPSESSID
* <p>
* 所以 直接设置成一级域名 ?
* 假如平台设置的是 .xxx.qpaas.com ,凤凰自己设置的是 .qpaas.com ,这样浏览器会保留几个?
* 更灵活一点,先取一下PHPSESSID,如果有,就按这个来设置?
* <p>
* 看起来还是不可控
* <p>
* 直接走配置,
* isAutoGetCookieDomain=true
* <p>
* isAutoGetCookieDomain=false
* domainName=xxx ( **** 发布的时候根据平台登录页面,观察平台的PHPSESSID对应Cookie的Domain **** )
*
* @return
*/
public String getCookieDomain() {
//domainName
return null;
}

/*
* 获取请求来源和业务代码堆栈
* TODO 可以通过切面处理 记录下sessionId或其他请求标识(尽量和登陆信息无关)
* TODO 另外貌似nginx也可以开启记录请求日志,包括记录参数,后期使用ELK查询分析。
* @return
*/
public static String getRequestSource() {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
StringBuilder lastInvoked = new StringBuilder();
int stackTraceLength = stackTraceElements.length;
//最多只记录3条
int maxRecordLength = 10;
//标记已保存的堆栈条数
int currentRecordLength = 0;
//获取最近的业务堆栈,其他堆栈跳过
boolean isTargetRecord = false;
for (int i = 1; i < stackTraceLength; i++) {
String se = stackTraceElements[i].toString();
if (currentRecordLength >= maxRecordLength) {
break;
}
if (se.contains("cn.jiangjiesheng") && !se.contains("$$") && !se.contains("getRequestSource")) {
isTargetRecord = true;
lastInvoked.append(stackTraceElements[i].toString());
lastInvoked.append("\n");
currentRecordLength++;
} else {
if (isTargetRecord) {
break;
}
}
}
if (lastInvoked.length() < 1 && stackTraceLength >= 4) {
lastInvoked.append(stackTraceElements[2].toString());
lastInvoked.append(stackTraceElements[3].toString());
}
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes == null) {
return "非web请求,调用链:\n" + lastInvoked.toString();
}
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
return "web请求:" + request.getRequestURL().toString() + ",调用链:\n" + lastInvoked.toString();
}

public static List<String> getStackTraceElement(){
StackTraceElement[] ss = Thread.currentThread().getStackTrace();
List<String> st = Lists.newArrayList();

for (StackTraceElement s : ss) {
if(s.toString().contains("edu")){
st.add(s.toString());
}
}
return st;
}

/**
* 培训实施开始前10分提醒 从主表取
* 培训课程和考试变化 实时取
* 培训实施发布取消发布 实时取
*
* 课程中心的课程分配 实时取
*
* 如果后期发现因为nginx代理导致url地址读取的并不准确,在相关业务接口中直接前端传参,后档落库,目前就是培训和课程
*
* @return
*/
public String getDomain() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes == null) {
// 这个不能静态方法调用
String domain = paasConfig.getHost();
// log.info("获取域名,HttpServletRequest为空,domain={}", domain);
return domain;
} else {
try {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();//.getResponse()
String requestURL = request.getRequestURL().toString();//完整的
String passHost = paasConfig.getHost();
// String requestURI = request.getRequestURI();
// String remoteAddr = request.getRemoteAddr();
// String basePath = request.getScheme() + "://" +
// request.getServerName() + ":" + request.getServerPort() +
// request.getContextPath() + "/";
// System.out.println(requestURI);
// System.out.println(requestURL);
// System.out.println(remoteAddr);
// System.out.println(domain1);
// System.out.println(basePath);
// 山西亚鑫 遇到的问题:
// 实际请求地址是:
// http://sc.sxyx.com.cn:8000/safetyjapi/edu/front/course/addUserLearningCourse
// 后端取到的地址是:(少了端口)
// requestURL=http://sc.sxyx.com.cn/safetyjapi/edu/front/course/addUserLearningCourse

// log.info("获取域名,HttpServletRequest不为空,获取requestURL成功,requestURL={}", requestURL);
//https://www.baidu.com/s?wd=%20request.getRequestURL()%20https%20%E4%B8%A2%E4%BA%86
int index = requestURL.indexOf("safetyjapi");
//局域网还是直接读取配置的中的
if (requestURL.contains("127.0.0.1") || requestURL.toLowerCase().contains("localhost")) {
//其实应该不返回域名,直接通过相对路径打开跳转
// log.info("获取域名,HttpServletRequest不为空,局域网环境,读取pass配置,domain={}", paasConfig.getHost());
return paasConfig.getHost();
}
//局域网还是直接读取配置的中的
if (index <= 2) {
//其实应该不返回域名,直接通过相对路径打开跳转
// log.info("获取域名,HttpServletRequest不为空,域名异常,读取pass配置,domain={}", paasConfig.getHost());
return paasConfig.getHost();
}
String domain = requestURL.substring(0, requestURL.indexOf("safetyjapi"));
//特别注意 paasConfig.getHost() 升级框架前的方法是没有的
if (domain.toLowerCase().contains("http:") && passHost.toLowerCase().startsWith("https:")) {
domain = domain.toLowerCase().replace("http:", "https:");
//因为 requestURL 拿不到https,所以和paas服务保持一致,
}

//如果domain和paasConfig.getHost()的域名部分相同,就直接返回paasConfig.getHost()(这个带端口)
//domain调试看到是带了服务本身端口,所以还是处理下保证没问题。
String domainOnly = domain.split(":").length == 3 ? domain.substring(0, domain.lastIndexOf(":")) :( domain.endsWith("/")?domain.substring(0,domain.lastIndexOf("/")):domain);
if(paasConfig.getHost().contains(domainOnly)){
// log.info("获取域名,HttpServletRequest不为空,读取的域名和paas配置相同,读取pass配置【会有端口号】,domain={}", paasConfig.getHost());
return paasConfig.getHost();
}

Integer paasHttpDomainPort = nacosConfig.getPaasHttpDomainPort();
if(paasHttpDomainPort != null){
//拿到的结果后面是带/的
domain = domain.substring(0, domain.length() - 1) + ":" + paasHttpDomainPort + "/";
}
// log.info("获取域名,HttpServletRequest不为空,获取域名成功,domain={}", domain);
return domain;
} catch (Exception ex) {
log.info("获取域名,出现异常,HttpServletRequest不为空,读取pass配置,domain={}", paasConfig.getHost(), ex);
return paasConfig.getHost();
}
}
}

public String getDomainByLocalThread() {
String domain = AyStatic.getDomainThreadLocal();
if (StringUtils.isNotBlank(domain)) {
// log.info("获取域名,从ThreadLocal获取到值(这个一定是对的),domain={}", domain);
return domain;
}
//重新取值不一定对。
// log.info("获取域名,从ThreadLocal未获取到值(重新取值),domain={}", domain);
return self.getDomain();
}

/**
* 线上图片转为byte数组
* https://blog.csdn.net/u011400521/article/details/103084913/
* @param path
* @return
*/
public static byte[] onlineImage2byte(String path) throws IOException {
byte[] data = null;
URL url = null;
InputStream input = null;
try{
url = new URL(path);
if (path.toLowerCase().startsWith("https")) {
HttpsURLConnection httpUrl = (HttpsURLConnection) url.openConnection();
httpUrl.setHostnameVerifier(new CustomizedHostnameVerifier());
httpUrl.connect();
httpUrl.getInputStream();
input = httpUrl.getInputStream();
} else {
//代码暂时只看这里
HttpURLConnection httpUrl = (HttpURLConnection) url.openConnection();
httpUrl.connect();
httpUrl.getInputStream();
input = httpUrl.getInputStream();
}
}catch (Exception e) {
e.printStackTrace();
return null;
}

ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int numBytesRead = 0;
while ((numBytesRead = input.read(buf)) != -1) {
output.write(buf, 0, numBytesRead);
}
data = output.toByteArray();
output.close();
input.close();
return data;
}

/**
* todo [1/2] 底层服务是https的,那nacos中一定要有用https开头
* @return
*/
private static HttpClientBuilder getHttpClientBuilder(){
//如果服务是https的,那请求一定要带上https
//即:
// project-metadata:
// domain: https://baoxianjiance-shukechanpinkaifa-wrrcyk.k8s-assembly-machine.qpaas.com # 外网域名
// internal-domain: https://baoxianjiance-shukechanpinkaifa-wrrcyk.k8s-assembly-machine.qpaas.com # 内网域名
//
SSLContext sslContext = null;
try {
sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
return true;
}
}).build();
} catch (Exception e) {
e.printStackTrace();
}
//创建httpClient
return HttpClients.custom().setSSLContext(sslContext).
setSSLHostnameVerifier(new NoopHostnameVerifier());
//————————————————
// 版权声明:本文为CSDN博主「185的阿平」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
// 原文链接:https://blog.csdn.net/weixin_42740540/article/details/128128394
}

/**
* todo [2/2] 底层服务是https的,那nacos中一定要有用https开头
* 非本类的HttpURLConnection,暂时没有改
* 未确定是否有效
* @return
*/
private static class CustomizedHostnameVerifier implements HostnameVerifier {

//重写验证方法
@Override
public boolean verify(String arg0, SSLSession arg1)
{
//所有都正确
return true;
}
}

}

```
### 2.RestTemplate

```
@Autowired
private RestTemplate restTemplate;


package cn.jiangjiesheng.inp.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;


@Configuration
public class RestTemplateConfig {
// 需要用的地方
// @Autowired
// private RestTemplate restTemplate;

@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory simpleClientHttpRequestFactory) {
//如果还有ssl有报错的话,就直接 传入 new RestTemplateSkipSslCheckClientHttpRequestFactory()
RestTemplate restTemplate = new RestTemplate(simpleClientHttpRequestFactory);
//默认编码是IOS-8859
restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("utf-8")));
// 移除fastJson配置 使用默认jackson 启用DateFormat注解
// FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
// List<MediaType> supportedMediaTypes = Lists.newArrayList();
// supportedMediaTypes.add(MediaType.APPLICATION_JSON);
// fastJsonHttpMessageConverter.setSupportedMediaTypes(supportedMediaTypes);
// restTemplate.getMessageConverters().add(1, fastJsonHttpMessageConverter);
return restTemplate;
}

@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
RestTemplateSkipSslCheckClientHttpRequestFactory factory = new RestTemplateSkipSslCheckClientHttpRequestFactory();
factory.setConnectTimeout(15000);
factory.setReadTimeout(15000);
return factory;
}
}



```

正文到此结束
本文目录