- Java发http请求
收到添加依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
HttpGet请求测试代码
public class HttpGetTest{
public static void main(String[] args) throws IOException {
//实例化HttpClient实例
CloseableHttpClient client = HttpClients.createDefault();
//请求url
String url = "https://www.baidu.com";
HttpGet httpGet = new HttpGet(url);
//添加请求头
httpGet.addHeader("Content-Type", "application/json");
httpGet.addHeader("Accept", "application/json");
//发起请求
CloseableHttpResponse response = client.execute(httpGet);
//获得请求状态码
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
//获得请求实体
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "utf-8");
System.out.println(result);
//获得所有请求头
Header[] allHeaders = response.getAllHeaders();
for (Header header : allHeaders) {
//请求头名称
String name = header.getName();
//请求头值
String value = header.getValue();
System.out.println(name + ":" + value);
}
}
}
}
HttpPost请求
package fmx.test.httptest;
import net.sf.json.JSONObject;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
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.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
/**
* @author fmx
* @version 1.0
* @date 2020/9/3 22:40
*/
public class HttpPostTest {
public static void main(String[] args) throws IOException {
//实例化HttpClient实例
CloseableHttpClient client = HttpClients.createDefault();
//请求url
String url = "https://www.baidu.com";
HttpPost httpPost = new HttpPost(url);
//添加请求头
httpPost.addHeader("Content-Type", "application/json");
httpPost.addHeader("Accept", "application/json");
//请求数据
Map<String, Object> map = new HashMap<>();
JSONObject x = JSONObject.fromObject(map);
String body = x.toString();
StringEntity strEntity = new StringEntity(body, Charset.forName("UTF-8"));
strEntity.setContentType("application/json");
httpPost.setEntity(strEntity);
//设置超时时间按
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(80000).setConnectTimeout(80000).build();
httpPost.setConfig(requestConfig);
//发起请求
CloseableHttpResponse response = client.execute(httpPost);
//获得请求状态码
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
//获得请求实体
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "utf-8");
System.out.println(result);
//获得所有请求头
Header[] allHeaders = response.getAllHeaders();
for (Header header : allHeaders) {
//请求头名称
String name = header.getName();
//请求头值
String value = header.getValue();
System.out.println(name + ":" + value);
}
}
}
}
- 接收请求(以微信支付回调为例)
@PostMapping("/payNotify")
public JSONObject wxNotify(HttpServletRequest request, HttpServletResponse response, @RequestHeader HttpHeaders headers) {
//返回通知的应答报文,code(32):SUCCESS为清算机构接收成功;message(64):错误原因
JSONObject responseJson = new JSONObject();
responseJson.put("code", "FAIL");
//支付通知http应答码为200或204才会当作正常接收,当回调处理异常时,应答的HTTP状态码应为500,或者4xx。
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
if (!headers.containsKey("Wechatpay-Serial") || !headers.containsKey("Wechatpay-Timestamp")
|| !headers.containsKey("Wechatpay-Nonce") || !headers.containsKey("Wechatpay-Signature")) {
log.info("请求头丢失");
responseJson.put("message", "回调请求header缺失");
return responseJson;
}
String wechatpaySerial = headers.getFirst("Wechatpay-Serial");//平台证书序列号
String wechatpayTimestamp = headers.getFirst("Wechatpay-Timestamp");//应答时间戳
String wechatpayNonce = headers.getFirst("Wechatpay-Nonce");//应答随机串
String wechatpaySignature = headers.getFirst("Wechatpay-Signature"); //应答签名
if (!MyWxPayConfig.WECHAT_CERTIFICATR_SERIAL_NO.equals(wechatpaySerial)) {
responseJson.put("message", "回调请求证书序列化不一致");
return responseJson;
}
log.info("WechatpaySignature{}", wechatpaySerial);
log.info("WechatpayTimestamp{}", wechatpayTimestamp);
log.info("WechatpayNonce{}", wechatpayNonce);
log.info("WechatpaySignature{}", wechatpaySignature);
try {
//获取微信POST过来反馈信息
Map<String, String> params = new HashMap<String, String>();
// post请求的密文数据
ServletInputStream in = request.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String sReqData = "";
String itemStr = "";//作为输出字符串的临时串,用于判断是否读取完毕
while (null != (itemStr = reader.readLine())) {
sReqData += itemStr;
}
log.info("resultData{}", sReqData);
//验签
byte[] signature = null;
try {
signature = Base64.getDecoder().decode(wechatpaySignature);
} catch (Exception e) {
e.printStackTrace();
log.info("响应签名Base64解码失败");
responseJson.put("message", "响应签名Base64解码失败");
return responseJson;
}
boolean verify = WxPayUtils.verify(wechatpayTimestamp, wechatpayNonce, sReqData, signature);
if (!verify) {
log.info("回调信息签名验证失败");
responseJson.put("message", "回调信息签名验证失败");
return responseJson;
}
JSONObject jsonObject = JSONObject.fromObject(sReqData);
Map<String, Object> m = (Map) jsonObject;
if (m.get("event_type") == null || !m.get("event_type").equals("TRANSACTION.SUCCESS")) {
//补充处理部分
response.setStatus(HttpServletResponse.SC_OK);
responseJson.put("code", "SUCCESS");
responseJson.put("message", "微信支付失败,商户处理成功");
}
String resource = m.get("resource").toString();
JSONObject resourcejso = JSONObject.fromObject(resource);
Map<Object, Object> mm = (Map) resourcejso;
String nonce = mm.get("nonce").toString();
String ciphertext = mm.get("ciphertext").toString();
String assc = mm.get("associated_data").toString();
String APIv3Key = MyWxPayConfig.API_V3_KEY;
//解密回调信息
byte[] key = APIv3Key.getBytes("UTF-8");
WxAPIV3AesUtil aesUtil = new WxAPIV3AesUtil(key);
String decryptToString = aesUtil.decryptToString(assc.getBytes("UTF-8"), nonce.getBytes("UTF-8"), ciphertext);
JSONObject decryption = JSONObject.fromObject(decryptToString);
Map<String, Object> decryptionMap = (Map) decryption;
System.out.println(decryptionMap);
if (decryptionMap.get("transaction_id") == null) {
log.info("未接受到微信订单号");
responseJson.put("message", "微信支付成功,未接受到微信订单号");
return responseJson;
}
if (decryptionMap.get("out_trade_no") == null) {
log.info("未接收到商家订单号");
responseJson.put("message", "微信支付成功,未接收到商家订单号");
return responseJson;
}
String outTradeNo = decryptionMap.get("out_trade_no").toString();
List<Integer> status = partyPaymentRecordService.getPaymentStatusByoutTradeNo(outTradeNo);
boolean flag = false;
if (status != null) {
for (Integer sta : status) {
if (sta != null && sta != 0) {
flag = true;
break;
}
}
}
if (flag) {
response.setStatus(HttpServletResponse.SC_OK);
responseJson.put("code", "SUCCESS");
responseJson.put("message", "微信支付成功");
return responseJson;
}
// statusCode
decryptionMap.put("statusCode", "200");
partyPaymentRecordService.trackOrder(decryptionMap, null);
System.out.println(decryptToString);
} catch (Exception e) {
e.printStackTrace();
}
log.info("微信支付成功");
response.setStatus(HttpServletResponse.SC_OK);
responseJson.put("code", "SUCCESS");
responseJson.put("message", "微信支付成功");
return responseJson;
}
}
- 若在开发环境中,则需交给spring管理
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource(value = "classpath:/properties/httpClient.properties")
public class HttpClientConfig {
@Value("${http.maxTotal}")
private Integer maxTotal; //最大连接数
@Value("${http.defaultMaxPerRoute}")
private Integer defaultMaxPerRoute; //最大并发链接数
@Value("${http.connectTimeout}")
private Integer connectTimeout; //创建链接的最大时间
@Value("${http.connectionRequestTimeout}")
private Integer connectionRequestTimeout; //链接获取超时时间
@Value("${http.socketTimeout}")
private Integer socketTimeout; //数据传输最长时间
@Value("${http.staleConnectionCheckEnabled}")
private boolean staleConnectionCheckEnabled; //提交时检查链接是否可用
//定义httpClient链接池
@Bean(name = "httpClientConnectionManager")
public PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager() {
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
manager.setMaxTotal(maxTotal); //设定最大链接数
manager.setDefaultMaxPerRoute(defaultMaxPerRoute); //设定并发链接数
return manager;
}
//定义HttpClient
/**
* 实例化连接池,设置连接池管理器。
* 这里需要以参数形式注入上面实例化的连接池管理器
*
* @Qualifier 指定bean标签进行注入
*/
@Bean(name = "httpClientBuilder")
public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager") PoolingHttpClientConnectionManager httpClientConnectionManager) {
//HttpClientBuilder中的构造方法被protected修饰,所以这里不能直接使用new来实例化一个HttpClientBuilder,可以使用HttpClientBuilder提供的静态方法create()来获取HttpClientBuilder对象
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClientBuilder.setConnectionManager(httpClientConnectionManager);
return httpClientBuilder;
}
/**
* 注入连接池,用于获取httpClient
*
* @param httpClientBuilder
* @return
*/
@Bean
public CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder) {
return httpClientBuilder.build();
}
/**
* Builder是RequestConfig的一个内部类
* 通过RequestConfig的custom方法来获取到一个Builder对象
* 设置builder的连接信息
*
* @return
*/
@Bean(name = "builder")
public RequestConfig.Builder getBuilder() {
RequestConfig.Builder builder = RequestConfig.custom();
return builder.setConnectTimeout(connectTimeout)
.setConnectionRequestTimeout(connectionRequestTimeout)
.setSocketTimeout(socketTimeout)
.setStaleConnectionCheckEnabled(staleConnectionCheckEnabled);
}
/**
* 使用builder构建一个RequestConfig对象
*
* @param builder
* @return
*/
@Bean
public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder) {
return builder.build();
}
}
import javax.annotation.PreDestroy;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.pool.PoolStats;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component //交给spring容器管理
public class HttpClientClose extends Thread {
@Autowired
private PoolingHttpClientConnectionManager manage;
private volatile boolean shutdown; //开关 volatitle表示多线程可变数据,一个线程修改,其他线程立即修改
public HttpClientClose() {
///System.out.println("执行构造方法,实例化对象");
//线程开启启动
this.start();
}
@Override
public void run() {
try {
//如果服务没有关闭,执行线程
while (!shutdown) {
synchronized (this) {
wait(5000); //等待5秒
//System.out.println("线程开始执行,关闭超时链接");
//关闭超时的链接
PoolStats stats = manage.getTotalStats();
int av = stats.getAvailable(); //获取可用的线程数量
int pend = stats.getPending(); //获取阻塞的线程数量
int lea = stats.getLeased(); //获取当前正在使用的链接数量
int max = stats.getMax();
//System.out.println("max/"+max+": av/"+av+": pend/"+pend+": lea/"+lea);
manage.closeExpiredConnections();
}
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
super.run();
}
//关闭清理无效连接的线程
@PreDestroy //容器关闭时执行该方法.
public void shutdown() {
shutdown = true;
synchronized (this) {
//System.out.println("关闭全部链接!!");
notifyAll(); //全部从等待中唤醒.执行关闭操作;
}
}
}
httpClient.properties
#最大连接数
http.maxTotal = 1000
#并发数
http.defaultMaxPerRoute = 20
#创建连接的最长时间
http.connectTimeout=5000
#从连接池中获取到连接的最长时间
http.connectionRequestTimeout=500
#数据传输的最长时间
http.socketTimeout=5000
#提交请求前测试连接是否可用
http.staleConnectionCheckEnabled=true
- 调用API
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
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.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@Service
public class HttpClientService {
@Autowired
private CloseableHttpClient httpClient;
@Autowired
private RequestConfig requestConfig;
/**
* 编辑工具API的目的简化代码,实现松耦合
* 作用:帮助用户发起http请求,获取正确的结果返回给用户 参数设计:
* 1.用户url地址
* 2.Map<参数名,参数值 > 3.字符集
*
* get请求方式: 1.无参数时:http://www.baidu.com
* 2.有参数时:http://www.baidu.com?key=--
*
* @param url
* @param params
* @param charset
* @return
*/
// 实现httpClient GET提交
public String doGet(String url, Map<String, String> params, String charset) {
String result = null;
// 1.判断字符集编码是否为空 如果为空则给定默认值utf-8
if (StringUtils.isEmpty(charset)) {
charset = "UTF-8";
}
// 2.判断用户是否需要传递参数
if (params != null) {
try {
URIBuilder uriBuilder = new URIBuilder(url);
for (Map.Entry<String, String> entry : params.entrySet()) {
uriBuilder.addParameter(entry.getKey(), entry.getValue());
}
// url?id=1&name=tom
url = uriBuilder.build().toString();
} catch (Exception e) {
e.printStackTrace();
}
}
// 3.定义参数提交对象
HttpGet get = new HttpGet(url);
// 4.为请求设定超时时间
get.setConfig(requestConfig);
// 5.通过httpClient发送请求
try {
CloseableHttpResponse response = httpClient.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
// 表示程序调用成功
result = EntityUtils.toString(response.getEntity(), charset);
} else {
System.out.println("调用异常:状态信息:" + response.getStatusLine().getStatusCode());
throw new RuntimeException();
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public String doGet(String url) {
return doGet(url, null, null);
}
public String doGet(String url, Map<String, String> params) {
return doGet(url, params, null);
}
public String doGet(String url, String charset) {
return doGet(url, null, charset);
}
// 实现httpClient POST提交
public String doPost(String url, Map<String, String> params, String charset) {
String result = null;
// 1.定义请求类型
HttpPost post = new HttpPost(url);
post.setConfig(requestConfig); // 定义超时时间
// 2.判断字符集是否为null
if (StringUtils.isEmpty(charset)) {
charset = "UTF-8";
}
// 3.判断用户是否传递参数
if (params != null) {
// 3.2准备List集合信息
List<NameValuePair> parameters = new ArrayList<>();
// 3.3将数据封装到List集合中
for (Map.Entry<String, String> entry : params.entrySet()) {
parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
// 3.1模拟表单提交
try {
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, charset); // 采用u8编码
// 3.4将实体对象封装到请求对象中
post.setEntity(formEntity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
// 4.发送请求
try {
CloseableHttpResponse response = httpClient.execute(post);
// 4.1判断返回值状态
if (response.getStatusLine().getStatusCode() == 200) {
// 4.2表示请求成功
result = EntityUtils.toString(response.getEntity(), charset);
} else {
System.out.println("获取状态码信息:" + response.getStatusLine().getStatusCode());
throw new RuntimeException();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
public String doPost(String url) {
return doPost(url, null, null);
}
public String doPost(String url, Map<String, String> params) {
return doPost(url, params, null);
}
public String doPost(String url, String charset) {
return doPost(url, null, charset);
}
}