发送http请求总结
最近在使用Apache的httpclient的时候,maven引用了最新版本4.3,发现Idea提示DefaultHttpClient等常用的类已经不推荐使用了,之前在使用4.2.3版本的时候,还没有被deprecated。去看了下官方文档,确实不推荐使用了:
DefaultHttpClient —> CloseableHttpClient
HttpResponse —> CloseableHttpResponse
详细链接:http://www.httpclient.cn/archives/96.html
这个说的也不错:https://www.jianshu.com/p/375be5929bed
使用httpclient发送get请求(完整样例):
public BestpayResult<String> doGetService(String Url, String param){ //首先需要先创建一个DefaultHttpClient的实例 HttpGet httpGet=null; try { //获得当前客户端对象, 用这种过时的方法创建客户端对象,只能用httpGet.abort();来关闭了,否则closeableHttpClient.close()来关闭 HttpClient httpClient = new DefaultHttpClient(); //备注:HttpClient httpClient = new DefaultHttpClient();已经过时了,new DefaultHttpClient();可以替换为HttpClients.createDefault(); //HttpClients.createDefault()实现的实际就是HttpClientBuilder.create().build(); //所以HttpClient httpClient =HttpClientBuilder.create().build();也是可以的 //先创建一个HttpGet对象,传入目标的网络地址,然后调用HttpClient的execute()方法即可: //根据地址获取请求 httpGet = new HttpGet(new StringBuilder(Url).append("?").append(param).toString()); //通过请求对象,获取响应对象 HttpResponse response = httpClient.execute(httpGet); //通过HttpResponse 的getEntity()方法获取返回信息 //下面这个可以获得状态码 int code=response.getStatusLine().getStatusCode(); if(code!=200){ return new BestpayResult<>(String.valueOf(code),"调用HttpGet请求失败"); } //获得返回的信息 HttpEntity entity = response.getEntity(); //防止空指针异常 if (entity != null) { //下面是读取返回信息内容的代码 InputStream is = entity.getContent(); BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8")); String line = br.readLine(); StringBuilder sb = new StringBuilder(); while (line != null) { sb.append(line + "\n"); line = br.readLine(); } br.close(); is.close(); return new BestpayResult<>("200000","成功",sb.toString()); } return new BestpayResult<>("200999","HttpGet响应entity内容为空"); }catch (Exception e){ e.printStackTrace(); return new BestpayResult<>("999999","HttpGt请求未知异常"); }finally { //最后要记得关闭 httpGet.abort(); } }
发送post请求
public BestpayResult<String> doService(String Url, String request) { System.out.println("请求翼支付的URL地址:"+Url); System.out.println("发送给翼支付的http请求报文:" + request); HttpPost httpPost = new HttpPost(Url); //配置请求 httpPost.setHeader("Content-Type","application/json"); //request就是参数了 StringEntity se = new StringEntity(request, "utf-8"); httpPost.setEntity(se); //HttpClients.createDefault();实现的就是HttpClientBuilder.create().build(); CloseableHttpClient closeableHttpClient= HttpClients.createDefault(); try { HttpResponse httpResponse=closeableHttpClient.execute(httpPost); //获得状态码 int code=httpResponse.getStatusLine().getStatusCode(); if (200==code){ //获得响应消息 HttpEntity entity=httpResponse.getEntity(); if (entity!=null){ String responseStr=EntityUtils.toString(httpResponse.getEntity(), "utf-8"); System.out.println("收到翼支付的http响应报文:"+responseStr); return new BestpayResult<>(String.valueOf(code),"调用Http服务成功!", responseStr); }else{ System.out.println("收到翼支付的http响应,但报文为空"); return new BestpayResult<>(String.valueOf(code),"调用Http服务成功!", null); } }else{ System.out.println("调用翼支付Http请求失败,失败码为:"+code); return new BestpayResult<>(String.valueOf(code),"调用Http服务失败!", null); } }catch (Exception e){ e.printStackTrace(); return new BestpayResult<>("999","调用Http服务失败!位置异常", null); } finally { if (closeableHttpClient!=null){ try { closeableHttpClient.close(); }catch (Exception e){ e.printStackTrace(); } } } }
httpGet.abort();表示终止终止此次get访问,意思就是此次请求终止
上面是最基本的请求,如果并发较大的话,则需要加连接池
连接池管理器默认的为2和20
那么如何为httpclient增加连接池管理器呢:https://www.cnblogs.com/wgslucky/p/11270038.html
package com.tencent.service; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NoHttpResponseException; import org.apache.http.client.HttpRequestRetryHandler; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.conn.ConnectionPoolTimeoutException; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLContextBuilder; import org.apache.http.conn.ssl.SSLContexts; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.SocketTimeoutException; import java.security.*; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.io.InterruptedIOException; import java.net.UnknownHostException; import javax.net.ssl.SSLException; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpRequest; import org.apache.http.client.protocol.HttpClientContext; /** * User: rizenguo * Date: 2014/10/29 * Time: 14:36 */ public class HttpsRequest implements IServiceRequest { private static final Logger log = LoggerFactory.getLogger(HttpsRequest.class); //表示请求器是否已经做了初始化工作 private boolean hasInit = false; //连接超时时间,默认10秒 private int socketTimeout = 10000; //传输超时时间,默认30秒 private int connectTimeout = 30000; //请求器的配置 private RequestConfig requestConfig; //HTTP请求器 private CloseableHttpClient httpClient; private PoolingHttpClientConnectionManager poolConnManager = new PoolingHttpClientConnectionManager(); public HttpsRequest() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException { this(false,null,null); } public HttpsRequest(boolean is_cert, String sslcert_path, String sslcert_password) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException { init(is_cert,sslcert_path,sslcert_password); } private void init(boolean is_cert, String sslcert_path, String sslcert_password) throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException { SSLContext sslcontext = null; if(is_cert) { KeyStore keyStore = KeyStore.getInstance("PKCS12"); FileInputStream instream = new FileInputStream(new File(sslcert_path));//加载本地的证书进行https加密传输 try { keyStore.load(instream, sslcert_password.toCharArray());//设置证书密码 } catch (CertificateException e) { log.error(e.getMessage(),e); } catch (NoSuchAlgorithmException e) { log.error(e.getMessage(),e); } finally { instream.close(); } // Trust own CA and all self-signed certs sslcontext = SSLContexts.custom() .loadKeyMaterial(keyStore, sslcert_password.toCharArray()) .build(); } else { try { sslcontext = new SSLContextBuilder().loadTrustMaterial( null, new TrustStrategy() { // 信任所有 @Override public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }).build(); } catch (KeyManagementException e) { log.error(e.getMessage(),e); } catch (NoSuchAlgorithmException e) { log.error(e.getMessage(),e); } catch (KeyStoreException e) { log.error(e.getMessage(),e); } } // Allow TLSv1 protocol only SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); // 设置最大连接数 poolConnManager.setMaxTotal(200); // 设置每个连接的路由数 poolConnManager.setDefaultMaxPerRoute(200); //根据默认超时限制初始化requestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout) .setConnectTimeout(connectTimeout) .setConnectionRequestTimeout(connectTimeout).build(); //请求失败时,进行请求重试 HttpRequestRetryHandler handler = new HttpRequestRetryHandler() { @Override public boolean retryRequest(IOException e, int i, HttpContext httpContext) { if (i > 3){ //重试超过3次,放弃请求 log.info("retry has more than 3 time, give up request"); return false; } if (e instanceof NoHttpResponseException){ //服务器没有响应,可能是服务器断开了连接,应该重试 log.info("receive no response from server, retry"); return true; } if (e instanceof SSLHandshakeException){ // SSL握手异常 log.info("SSL hand shake exception"); return false; } if (e instanceof InterruptedIOException){ //超时 log.info("InterruptedIOException"); return false; } if (e instanceof UnknownHostException){ // 服务器不可达 log.info("server host unknown"); return false; } if (e instanceof ConnectTimeoutException){ // 连接超时 log.info("Connection Time out"); return false; } if (e instanceof SSLException){ log.info("SSLException"); return false; } HttpClientContext context = HttpClientContext.adapt(httpContext); HttpRequest request = context.getRequest(); if (!(request instanceof HttpEntityEnclosingRequest)){ //如果请求不是关闭连接的请求 return true; } return false; } }; httpClient = HttpClients.custom() .setSSLSocketFactory(sslsf)
//添加加连接池管理器
.setConnectionManager(poolConnManager)
//为客户端配置超时时间。个人理解,这儿配置了,和在具体的post上请求是一样的,这:httpPost.setConfig(requestConfig);
.setDefaultRequestConfig(requestConfig)
//重试机制:https://www.jianshu.com/p/6a41c95855e3
.setRetryHandler(handler)
//连接池共享
.setConnectionManagerShared(true).build();
hasInit = true;
} /** * 通过Https往API post xml数据 * * @param url API地址 * @param xmlObj 要提交的XML数据对象 * @return API回包的实际数据 * @throws IOException * @throws KeyStoreException * @throws UnrecoverableKeyException * @throws NoSuchAlgorithmException * @throws KeyManagementException */ public String sendPost(String url, boolean is_cert, String sslcert_path, String sslcert_password, Object xmlObj) throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException { if (!hasInit) { init(is_cert,sslcert_path,sslcert_password); } String result = null; HttpPost httpPost = new HttpPost(url); //解决XStream对出现双下划线的bug XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_"))); xStreamForRequestPostData.alias("xml",xmlObj.getClass()); //将要提交给API的数据对象转换成XML格式数据Post给API String postDataXML = xStreamForRequestPostData.toXML(xmlObj); // log.info("API,POST过去的数据是:{}",postDataXML); //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别 StringEntity postEntity = new StringEntity(postDataXML, "UTF-8"); httpPost.addHeader("Content-Type", "text/xml"); // httpPost.addHeader("Connection","Keep-Alive"); // httpPost.addHeader("Keep-alive","19000"); httpPost.setEntity(postEntity); //设置请求器的配置 httpPost.setConfig(requestConfig); //log.info("executing request " + httpPost.getRequestLine()); CloseableHttpResponse response=null; try { response = httpClient.execute(httpPost); // HttpResponse response = httpClient.execute(httpPost); HttpEntity entity = response.getEntity(); result = EntityUtils.toString(entity, "UTF-8"); } catch (ConnectionPoolTimeoutException e) { log.info("http get throw ConnectionPoolTimeoutException(wait time out)"); } catch (ConnectTimeoutException e) { log.info("http get throw ConnectTimeoutException"); } catch (SocketTimeoutException e) { log.info("http get throw SocketTimeoutException"); } catch (Exception e) { log.info("http get throw Exception"); log.info("http get throw Exception异常信息为:"+e.getMessage()); log.info("http get throw Exception异常信息为:"+e.getCause()); } finally { try { if(response != null) { response.close(); } if(httpClient!=null){ httpClient.close(); } } catch (IOException e) { e.printStackTrace(); } httpPost.abort(); } return result; } /** * 设置连接超时时间 * * @param socketTimeout 连接时长,默认10秒 */ public void setSocketTimeout(int socketTimeout) { socketTimeout = socketTimeout; resetRequestConfig(); } /** * 设置传输超时时间 * * @param connectTimeout 传输时长,默认30秒 */ public void setConnectTimeout(int connectTimeout) { connectTimeout = connectTimeout; resetRequestConfig(); } private void resetRequestConfig(){ requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build(); } /** * 允许商户自己做更高级更复杂的请求器配置 * * @param requestConfig 设置HttpsRequest的请求器配置 */ public void setRequestConfig(RequestConfig requestConfig) { requestConfig = requestConfig; } }
posted on 2019-06-28 14:02 Cherishforchen 阅读(616) 评论(0) 编辑 收藏 举报