发送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 + "
");
                    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;
    }
}




原文地址:https://www.cnblogs.com/cherishforchen/p/11102305.html