Springcloud学习笔记42--利用HttpClient实现服务A向服务B发送Http请求,HttpUtil
1.StringEntity 和 UrlEncodedFormEntity 的区别
1.1 StringEntity
HTTPClient进行body传参,要使用StringEntity,而不要使用UrlEncodedFormEntity
后台方法的参数可以直接是一个对象
原因:UrlEncodedFormEntity会以字符串键值对形式传给后台,即:{"a":"value1", "b":"value2"},传给java方法,接收到的参数是:a=value1&b=value2,即它不支持json参数传递;
StringEntity传参:
String param = "{\"a\":\"value1\", \"b\":\"value2\"}";
httpPost.setEntity(new StringEntity(jsonParams, ContentType.create("application/json", "UTF-8")));
//后台方法的参数可以直接是一个对象
@PostMapping(value = "/methodxxx")
public Response methodxxx(@RequestBody Paramxxx param){
……
}
//paramxxx对象类:
class Paramxxx{
private String a;
private String b;
//getter
……
//setter
……
}
UrlEncodedFormEntity传参:
MapparamsMap = new HashMap<>(); paramsMap.put("a","value1"); paramsMap.put("b","value2"); if(null != paramsMap && paramsMap.size() > 0) { List nvps = new ArrayList<>(); for (String key : paramsMap.keySet()) { nvps.add(new BasicNameValuePair(key, String.valueOf(paramsMap.get(key)))); } httpPost.setEntity(new UrlEncodedFormEntity(nvps, Const.CHARSET)); } //后台接收的参数 @PostMapping(value = "/methodxxx") public Response methodxxx(String a, String b){ …… }
2.HttpUtil
package com.ttbank.flep.util; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang.StringUtils; import org.apache.http.*; import org.apache.http.client.HttpRequestRetryHandler; 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.client.methods.HttpRequestBase; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.LayeredConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.cookie.Cookie; 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.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.SSLException; import javax.net.ssl.SSLHandshakeException; import java.io.IOException; import java.io.InterruptedIOException; import java.net.UnknownHostException; import java.util.*; public class HttpUtil { private static final Logger logger = LoggerFactory.getLogger(HttpUtil.class); static final int timeOut = 25 * 1000; private static BasicCookieStore cookieStore = new BasicCookieStore(); private static CloseableHttpClient httpClient = null; private static ObjectMapper objectMapper = new ObjectMapper(); private final static Object syncLock = new Object(); private static void config(HttpRequestBase httpRequestBase, String headData, String contentType, String charset) throws Exception { // 设置Header等 httpRequestBase .setHeader( "Accept", "text/html,application/json,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); httpRequestBase.setHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"); httpRequestBase.setHeader("Accept-Charset", "ISO-8859-1,utf-8,gbk,gb2312;q=0.7,*;q=0.7"); httpRequestBase.setHeader("Content-Type", contentType); httpRequestBase.setHeader("CharacterEncoding", charset); // 处理特殊头信息 if (!StringUtils.isBlank(headData)) { String[] hStrings = headData.split("#"); if (hStrings.length > 0) { for (String hstring : hStrings) { String[] perStrings = hstring.split("@"); if (perStrings.length != 2) { logger.info("HttpUtils-->config-->hstring信息:" + perStrings); } httpRequestBase.setHeader(perStrings[0], perStrings[1]); } } else { logger.info("HttpUtils-->config-->headData信息:" + headData); } } // 请求的超时设置 RequestConfig config = RequestConfig.custom() .setConnectionRequestTimeout(timeOut) .setConnectTimeout(timeOut).setSocketTimeout(timeOut).build(); httpRequestBase.setConfig(config); } /** * 获取CloseableHttpClient对象 * @param url 常规格式是http://127.0.0.1:9002/ * @return */ public static CloseableHttpClient getHttpClient(String url) { String hostname = ""; String[] split = url.split("//"); if (split.length == 1) { hostname = split[0].split("/")[0]; } else { hostname = split[1].split("/")[0]; } int port = 80; if (hostname.contains(":")) { String[] arr = hostname.split(":"); hostname = arr[0]; port = Integer.parseInt(arr[1]); } //双重锁校验,多线程安全,单例模式 if (httpClient == null) { synchronized (syncLock) { if (httpClient == null) { httpClient = createHttpClient(500, 100, 200, hostname, port); } } } return httpClient; } /** * 创建HttpClient对象 * * @Title: createHttpClient * @param maxTotal * @param maxPerRoute * @param maxRoute * @param hostname * @param port * @return */ public static CloseableHttpClient createHttpClient(int maxTotal, int maxPerRoute, int maxRoute, String hostname, int port) { ConnectionSocketFactory plainsf = PlainConnectionSocketFactory .getSocketFactory(); LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory .getSocketFactory(); Registryregistry = RegistryBuilder . create().register("http", plainsf) .register("https", sslsf).build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager( registry); // 将最大连接数增加 cm.setMaxTotal(maxTotal); // 将每个路由基础的连接增加 cm.setDefaultMaxPerRoute(maxPerRoute); HttpHost httpHost = new HttpHost(hostname, port); // 将目标主机的最大连接数增加 cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute); // 请求重试处理 HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { if (executionCount >= 5) {// 如果已经重试了5次,就放弃 return false; } if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接,那么就重试 return true; } if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常 return false; } if (exception instanceof InterruptedIOException) {// 超时 return false; } if (exception instanceof UnknownHostException) {// 目标服务器不可达 return false; } if (exception instanceof ConnectTimeoutException) {// 连接被拒绝 return false; } if (exception instanceof SSLException) {// SSL握手异常 return false; } HttpClientContext clientContext = HttpClientContext .adapt(context); HttpRequest request = clientContext.getRequest(); // 如果请求是幂等的,就再次尝试 if (!(request instanceof HttpEntityEnclosingRequest)) { return true; } return false; }; }; CloseableHttpClient httpClient = HttpClients.custom() .setDefaultCookieStore(cookieStore).setConnectionManager(cm) .setRetryHandler(httpRequestRetryHandler).build(); return httpClient; } /** * POST请求 * * @Title: sendPost * @param url * 请求URL * @param params * 请求数据 * @param contentType * 请求MIME类型 * @param respContentType * 响应MIME类型 * @param headData * 请求头信息 * @return * @throws Exception */ public static Object sendPost(String url, Object params, String contentType, String respContentType, String headData) throws Exception { // if (url.contains("http://192.68.70.150:7004")) { // url = "http://158.58.13.37:8080" + url.substring(25); // } HttpPost httpPost = new HttpPost(url); config(httpPost, headData, contentType, "UTF-8"); CloseableHttpResponse response = null; Object t = null; try { // if (!StringUtils.isEmpty(headData) && headData.contains("Content-Type@application/x-www-form-urlencoded")) { // 装填参数 List nvps = new ArrayList (); /*Iterator it = ((HashMap ) params).entrySet() .iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); Object key = entry.getKey(); Object value = entry.getValue(); nvps.add(new BasicNameValuePair((String) key, (String) value)); } */ Set> entries = ((HashMap ) params).entrySet(); for (Map.Entry entry : entries) { Object key = entry.getKey(); Object value = entry.getValue(); nvps.add(new BasicNameValuePair((String) key, (String) value)); } // 设置参数到请求对象中 httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8")); logger.info("HttpUtils-->sendPost-->请求服务参数{}", nvps.toString()); } else { String data = objectMapper.writeValueAsString(params); logger.info("HttpUtils-->sendPost-->请求服务参数{}", data); httpPost.setEntity(new StringEntity(data, "UTF-8")); } logger.info("HttpUtils-->sendPost-->请求服务URL:" + url); response = getHttpClient(url).execute(httpPost); int httpStatusCode = response.getStatusLine().getStatusCode(); if (200 == httpStatusCode) { if (url.contains("login")) { List cookies = cookieStore.getCookies(); String cookieData = cookies.get(0).getName() + "=" + cookies.get(0).getValue(); return cookieData; } HttpEntity entity = response.getEntity(); t = convertEntity(entity, respContentType, "UTF-8"); } else { logger.error("请求服务URL[" + url + "]状态错误!错误状态号:[" + response.getStatusLine() + "]"); } } catch (Exception e) { logger.error("{}",e); } finally { try { if (response != null) response.close(); } catch (IOException e) { logger.error("{}",e); } } return t; } /** * 转换请求结果 * * @Title: convertEntity * @param entity * 响应体 * @param contentType * MIME类型 * @param charSet * MIME编码 * @return * @throws Exception */ private static Object convertEntity(HttpEntity entity, String contentType, String charSet) throws Exception { String reValue = ""; String errMsg = ""; try { reValue = (entity == null) ? null : EntityUtils.toString(entity, charSet); EntityUtils.consume(entity); logger.info("HttpUtils-->convertEntity-->服务返回:" + reValue); if (!StringUtils.isBlank(reValue)) { // 处理服务返回数据 // reValue = reValue.replace("\"null\"", // "\"\"").replace(":null", // ":\"\""); Object object = null; // 将json字符串转Map object = objectMapper.readValue(reValue, Map.class); return object; } } catch (ParseException e) { errMsg = e.getMessage(); logger.error("HttpUtils-->convertEntity-->服务返回结果转换异常:" + errMsg); } catch (IOException e) { errMsg = e.getMessage(); logger.error("HttpUtils-->convertEntity-->服务返回IO异常:" + errMsg); }catch (Exception e) { errMsg = e.getMessage(); logger.error("HttpUtils-->convertEntity-->服务返回结果转换异常2:" + errMsg); } return reValue; } /** * 发送GET请求 * * @Title: get * @param url * @return */ public static Object sendGet(String url, String headData) throws Exception { HttpGet httpget = new HttpGet(url); config(httpget, headData, "application/json", "UTF-8"); CloseableHttpResponse response = null; Object t = null; try { logger.info("HttpUtils-->sendGet-->请求服务URL:{}", url); response = getHttpClient(url).execute(httpget, HttpClientContext.create()); int httpStatusCode = response.getStatusLine().getStatusCode(); if (200 == httpStatusCode) { HttpEntity entity = response.getEntity(); t = convertEntity(entity, "application/json", "UTF-8"); } else { logger.error("请求服务URL[" + url + "]状态错误!错误状态号:[" + response.getStatusLine() + "]"); } } catch (Exception e) { logger.error("{}", e); } finally { try { if (response != null) response.close(); } catch (IOException e) { logger.error("{}", e); } } return t; } }
3.具体使用案例
package com.ttbank.flep.controller; import com.hzbank.flep.entity.SdkTestParams; import com.ttbank.flep.entity.Param; import com.ttbank.flep.util.HttpUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @Author lucky * @Date 2022/3/9 10:29 */ @Slf4j @RestController @RequestMapping("/cloud/discovery") public class DiscoveryServiceController { @Autowired DiscoveryClient discoveryClient; @PostMapping("/getNacosServiceInfo") public void getNacosServiceInfo(){ Listservices = discoveryClient.getServices(); services.stream().filter(item -> item.equals("FEIA")).findFirst().map(service -> { List instances = discoveryClient.getInstances(service); return null; }); System.out.println(services); } @PostMapping("/innerFileUpload") public void innerFileUpload(@RequestBody Param param){ log.info("subsysCode:{}",param.getSubsysCode()); } @PostMapping("/dedicateFileUpload") public void innerFileUpload(@RequestParam String subsysCode,@RequestParam String contentId){ log.info("subsysCode:{}",subsysCode); log.info("contentId:{}",contentId); } @PostMapping("/getFileInfo") public void getFileInfo(@RequestParam String url){ //String url="http://127.0.0.1:9002/cloud/discovery/innerFileUpload"; String headData="Content-Type@application/x-www-form-urlencoded"; Map params=new HashMap<>(); params.put("subsysCode","STPM" ); params.put("contentId","10000001" ); try { Object o = HttpUtil.sendPost(url, params, "application/json", "", headData); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { System.out.println("11111111111111122222333333"); System.out.println("plj6666888"); System.out.println("20220427_20_20"); } }