package com.pay.paydemo.utils;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
/**
* @ClassName:HttpClientManager
* @Description:httpClient客戶端 post entity的幾種形式:
* BasicHttpEntity 代表底層流的基本實體 InputStream流數據
* ByteArrayEntity 從指定的字節數組中取出內容的實體
* StringEntity 自我包含的可重復的實體,格式靈活(json、xml等)
* InputStreamEntity 流式不可以重復的實體
* UrlEncodedFormEntity 數據為鍵值對
*/
public class HttpClientManager {
private static final Logger logger = LoggerFactory.getLogger(HttpClientManager.class);
private static HttpClientManager httpClientManager = new HttpClientManager();
private static HttpClient httpClient = HttpClientManager.createHttpclient();
// 創建 httpClient
private static HttpClient createHttpclient(int connectTimeout, int connectionRequestTimeout) {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(500); // 最大連接數
cm.setDefaultMaxPerRoute(200);
// cm.setValidateAfterInactivity(2000);//設置空閑連接回收時間(單位ms),默認2000 連接是放linklist,使用的時候檢查是否過期,拿到可用的連接會從頭部移到尾部,所以回收時間會影響到服務器存在CLOSE_WAIT的個數
// CookieStore cookieStore = new BasicCookieStore();
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(connectTimeout) //請求超時時間
.setSocketTimeout(10 * 1000) //等待數據超時時間
.setConnectionRequestTimeout(connectionRequestTimeout) //獲取連接超時時間
.build();
return HttpClients.custom()
.setConnectionManager(cm)
.setDefaultRequestConfig(requestConfig)
// .setDefaultCookieStore(cookieStore) //設置cookie保持會話
.build();
}
// 創建 httpClient
private static HttpClient createHttpclient() {
return createHttpclient(5 * 1000, 3 * 1000);
}
private HttpClientManager() {
}
public static HttpClientManager getInstance() {
return HttpClientManager.httpClientManager;
}
public static String httpGet(String url, String returnCharset) throws IOException {
return httpGet(url, returnCharset, 5000);
}
public static String httpGet(String url, String returnCharset, int connectTimeout) throws IOException {
logger.info("請求URL:" + url);
long ls = System.currentTimeMillis();
HttpGet httpGet = null;
String result = "";
try {
httpGet = new HttpGet(url);
HttpResponse response = createHttpclient(connectTimeout, connectTimeout).execute(httpGet);
for (Header header : response.getAllHeaders()) {
logger.debug(header.getName() + ":" + header.getValue());
}
int code = response.getStatusLine().getStatusCode();
logger.info("服務器返回的狀態碼為:" + code);
HttpEntity entity = response.getEntity();
if (code == HttpStatus.SC_OK || entity != null) {// 如果請求成功
if (S.isBlank(returnCharset)) {
result = EntityUtils.toString(response.getEntity(), "UTF-8");
} else {
result = EntityUtils.toString(response.getEntity(), returnCharset);
}
}
} finally {
if (null != httpGet) {
httpGet.releaseConnection();
}
long le = System.currentTimeMillis();
logger.info("返回數據為:" + result);
logger.info("http請求耗時:" + (le - ls) + "ms");
}
return result;
}
/**
* @param url 請求url
* @param s 請求數據
* @param contentType
* @return String
* @throws
* @Title: httpPost
* @Description: http post請求,
* StringEntity Content-Type=application/json;charset=utf-8
*/
public static String httpPost(String url, String s, String contentType) throws IOException {
logger.info("請求URL:{},{}", url, s);
long ls = System.currentTimeMillis();
HttpPost httpPost = null;
String result = "";
try {
httpPost = new HttpPost(url);
StringEntity param = new StringEntity(s, "UTF-8");
param.setContentEncoding("UTF-8");
httpPost.setEntity(param);
if (S.isBlank(contentType)) {
httpPost.setHeader("Content-Type", "application/json;charset=utf-8");
} else {
httpPost.setHeader("Content-Type", contentType);
}
HttpResponse response = httpClient.execute(httpPost);
int code = response.getStatusLine().getStatusCode();
logger.info("服務器返回的狀態碼為:{}", code);
if (code == HttpStatus.SC_OK) {// 如果請求成功
result = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} finally {
if (null != httpPost) {
httpPost.releaseConnection();
}
long le = System.currentTimeMillis();
logger.info("返回數據為:{}", result);
logger.info("http請求耗時: {} ms", (le - ls));
}
return result;
}
/**
* @param @param url
* @param @return
* @return String
* @throws
* @Title: httpPostWithHead
* @Description: http post請求,能自定義請求頭
* ByteArrayEntity Content-Type=utf-8
*/
public static String httpPostWithHead(String url, Map<String, Object> headers, String body) {
logger.info("請求URL:{},請求head:{},請求數據:{}", url, headers, body);
long ls = System.currentTimeMillis();
HttpPost post = null;
String result = "";
try {
post = new HttpPost(url);
for (Map.Entry<String, Object> e : headers.entrySet()) {
post.addHeader(e.getKey(), String.valueOf(e.getValue()));
}
post.setEntity(new ByteArrayEntity(body.getBytes("utf-8")));
HttpResponse response = httpClient.execute(post);
for (Header header : response.getAllHeaders()) {
logger.info(header.getName() + ":" + header.getValue());
}
int code = response.getStatusLine().getStatusCode();
logger.info("服務器返回的狀態碼為:" + code);
if (code == HttpStatus.SC_OK) {// 如果請求成功
result = EntityUtils.toString(response.getEntity(), "UTF-8");
}
return result;
} catch (Exception e) {
logger.error(e.getMessage());
return result;
} finally {
if (null != post) {
post.releaseConnection();
}
long le = System.currentTimeMillis();
logger.info("返回數據為:" + result);
logger.info("http請求耗時:" + (le - ls) + "ms");
}
}
/**
* @param @param params
* @param @return
* @return List<NameValuePair>
* @throws @Title: transformMap
* @Description: 轉換post請求參數
*/
private static List<NameValuePair> transformMap(Map<String, String> params) {
if (params == null || params.size() < 0) {// 如果參數為空則返回null;
return new ArrayList<NameValuePair>();
}
List<NameValuePair> paramList = new ArrayList<NameValuePair>();
for (Map.Entry<String, String> map : params.entrySet()) {
paramList.add(new BasicNameValuePair(map.getKey(), map.getValue()));
}
return paramList;
}
/**
* @param @param url
* @param @return
* @return String
* @throws
* @Title: httpPost
* @Description: http post請求,
* UrlEncodedFormEntity Content-Type=application/x-www-form-urlencoded
*/
public static String httpPostByForm(String url, Map<String, String> formParam) throws IOException {
return httpPostbyFormHasProxy(url, formParam, null, null, null);
}
/*
* returnCharset 指定返回報文編碼
* */
public static String httpPostByForm(String url, Map<String, String> formParam, String returnCharset, String head) throws IOException {
return httpPostbyFormHasProxy(url, formParam, null, returnCharset, head);
}
/**
* @param @param url
* @param @param formParam
* @param @param proxy
* @param @return
* @return String
* @throws
* @Title: httpPost
* @Description: http post請求
* UrlEncodedFormEntity Content-Type=application/x-www-form-urlencoded
*/
public static String httpPostbyFormHasProxy(String url, Map<String, String> formParam, HttpHost proxy, String returnCharset, String head) throws IOException {
logger.info("請求URL:{}", url);
long ls = System.currentTimeMillis();
HttpPost httpPost = null;
String result = "";
try {
httpPost = new HttpPost(url);
if (!S.isBlank(head)) {
httpPost.setHeader("Referer", head);
}
if (proxy != null) {
RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
httpPost.setConfig(config);
}
List<NameValuePair> paramList = transformMap(formParam);
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(paramList, "utf8");
httpPost.setEntity(formEntity);
HttpResponse httpResponse = httpClient.execute(httpPost);
int code = httpResponse.getStatusLine().getStatusCode();
logger.info("服務器返回的狀態碼為:{}", code);
if (code == HttpStatus.SC_OK) {// 如果請求成功
if (S.isBlank(returnCharset)) {
result = EntityUtils.toString(httpResponse.getEntity());
} else {
result = EntityUtils.toString(httpResponse.getEntity(), returnCharset);
}
}
/* 303和307是HTTP1.1新加的服務器響應文檔的狀態碼,它們是對HTTP1.0中的302狀態碼的細化,主要用在對非GET、HEAD方法的響應上。
* 302 必須跟用戶確認是否該重發,因為第二次POST時,環境可能已經發生變化(嗯,POST方法不是冪等的),POST操作會不符合用戶預期。但是,很多瀏覽器(user agent我描述為瀏覽器以方便介紹)在這種情況下都會把POST請求變為GET請求
* 303 POST重定向為GET
* 307 當客戶端的POST請求收到服務端307狀態碼響應時,需要跟用戶詢問是否應該在新URI上發起POST方法,也就是說,307是不會把POST轉為GET的
* */
if (code == 307) {
Header header = httpResponse.getFirstHeader("Location");
logger.info("redirect url: " + header.getValue());
result = httpPostbyFormHasProxy(header.getValue(), formParam, null, returnCharset, head);
} else if (code == 302) {
Header header = httpResponse.getFirstHeader("Location");
logger.info("redirect url: " + header.getValue());
if (header.getValue().startsWith("/Cashier/Error.aspx") || header.getValue().startsWith("/Common/H5/Error.aspx?")) {
String s = header.getValue().split("\\?")[1].split("=")[1];
return unicode2String(s);
}
if (header.getValue().startsWith("https://") || header.getValue().startsWith("http://")) {
return header.getValue();
}
String targetUrl = "https://pay.heepay.com/" + header.getValue();
if (header.getValue().contains("/MSite/Cashier/AliPayWapPay")) {
return targetUrl;
}
result = httpPostbyFormHasProxy(targetUrl, formParam, null, returnCharset, head);
} else if (code == 303) {
Header header = httpResponse.getFirstHeader("Location");
logger.info("redirect url: " + header.getValue());
result = httpGet(header.getValue(), null);
}
} finally {
if (null != httpPost) {
httpPost.releaseConnection();
}
long le = System.currentTimeMillis();
logger.info("返回數據為:{}", result);
logger.info("http請求耗時:ms", (le - ls));
}
return result;
}
public static String unicode2String(String unicode) {
if (unicode.contains("%"))
unicode = unicode.replaceAll("%", "\\\\");
StringBuilder string = new StringBuilder();
String[] hex = unicode.split("\\\\u");
for (int i = 1; i < hex.length; i++) {
// 轉換出每一個代碼點
int data = Integer.parseInt(hex[i], 16);
string.append((char) data);
}
return string.toString();
}
public static JSONObject postWithJson(String url, String json) {
String retMsg = null;
try {
retMsg = httpPost(url, json, null);
} catch (IOException e) {
logger.error("HttpClientManager>>postWithJson>>請求失敗!", e);
}
if (!S.isBlank(retMsg)) {
return JSONObject.parseObject(retMsg);
}
return null;
}
public static String postJson(String url, String s, BiConsumer<Integer, String> consumer) {
HttpPost httpPost = new HttpPost(url);
logger.debug("請求的參數為: {}", s);
StringEntity param = new StringEntity(s, "utf-8");
param.setContentEncoding("utf-8");
httpPost.setEntity(param);
httpPost.setHeader("Content-Type", "application/json;charset=utf-8");
String result = null;
try {
HttpResponse response = httpClient.execute(httpPost);
int code = response.getStatusLine().getStatusCode();
logger.debug("服務器返回的狀態碼為:", code);
if (code == HttpStatus.SC_OK) {// 如果請求成功
result = EntityUtils.toString(response.getEntity(), "utf-8");
logger.debug("返回數據為:{}", result);
}
if (consumer != null)
consumer.accept(code, result);
} catch (Exception e) {
logger.info("發送通知報文異常", e);
} finally {
httpPost.releaseConnection();
}
return result;
}
}
支付寶請求:
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
AlipayClient alipayClient = new DefaultAlipayClient(map.get("requestUrl"), map.get("merNo"), map.get("sk"),
"json", ConstantPay.CHARSET_UTF8, map.get("publicKey"), getRSAType(map.get("signType"))); // 獲得初始化的AlipayClient
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();// 創建API對應的request類
request.setNotifyUrl(getCallbackUrl(map.get("billId"), map.get("appId"), map.get("notifyUrl")));
request.setBizContent(getBizContent(map));// 設置業務參數
Map<String, String> result = new HashMap<String, String>();
AlipayTradePrecreateResponse response = alipayClient.execute(request);
logger.info("ALIGF pay result:" + response.getBody());
if (null != response) {
Map<String, Object> mapTypes = JSON.parseObject(response.getBody());}