HttpClient(学习笔记)

11 篇文章 0 订阅
2 篇文章 0 订阅

HttpClient(学习笔记)

HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。HttpClient已经应用在很多的项目中,比如Apache Jakarta上很著名的另外两个开源项目Cactus和HTMLUnit都使用了HttpClient

一: 依赖

		<dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.11</version>
        </dependency>

二: 简单发送无参数GET请求

	@Test
    public void test1() throws Exception {
        //1.创建HTTP请求客户端
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //2.创建发送Get请求对象
        HttpGet httpGet = new HttpGet("http://localhost:8080/nolanj");
        //请求配置使用默认
        httpGet.setConfig(RequestConfig.DEFAULT);
        //3.执行请求, 获取响应对象response
        CloseableHttpResponse response = httpClient.execute(httpGet);
        //4.获取响应内容实体
        HttpEntity responseEntity = response.getEntity();
        //5.解析内容为字符串  读取完毕后会将流关闭
        String string = EntityUtils.toString(responseEntity,"utf-8");
        //6.释放资源
        httpClient.close();
    }

三: 简单发送有参数GET请求

 	@Test
    public void test1() throws Exception {
        //构造请求参数
        StringBuffer buffer = new StringBuffer();
        Map<String,String> paramsMap = new HashMap<>();
        paramsMap.put("name","张先生");
        paramsMap.put("age","25");
        paramsMap.put("sex","男");
        //进行参数拼接 name=xxx&age=xxx
        buffer.append("?");
        for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
            buffer.append(entry.getKey()).append("=")
                    .append(entry.getValue()).append("&");
        }
        //删除拼接完成后的最后一个 '&'
        buffer.deleteCharAt(buffer.length()-1);
        //1.创建HTTP请求客户端
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //2.创建发送Get请求对象											//拼接参数
        HttpGet httpGet = new HttpGet("http://localhost:8080/nolanj"+buffer.toString());
        //请求配置使用默认
        httpGet.setConfig(RequestConfig.DEFAULT);
        //5.执行请求, 获取响应对象response
        CloseableHttpResponse response = httpClient.execute(httpGet);
        //6.获取响应内容实体
        HttpEntity responseEntity = response.getEntity();
        //7.解析内容为字符串  读取完毕后会将流关闭
        String string = EntityUtils.toString(responseEntity,"utf-8");
        //8.释放资源
        httpClient.close();
    }

四: 简单发送参数为表单格式POST请求

	@Test
    public void test1() throws Exception {
        //1.创建HTTP请求客户端
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //2.创建发送post请求对象
        HttpPost httpPost = new HttpPost("http://localhost:8080/byte");
        //请求配置使用默认
        httpPost.setConfig(RequestConfig.DEFAULT);
        //构造请求参数
        LinkedList<NameValuePair> parameters = new LinkedList<>();
        parameters.add(new BasicNameValuePair("name","张韶涵"));
        //3.创建表单实体请求参数对象
        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters,"utf-8");
        //4.添加请求参数实体
        httpPost.setEntity(entity);
        //5.执行请求, 获取响应对象response
        CloseableHttpResponse response = httpClient.execute(httpPost);
        //6.获取响应内容实体
        HttpEntity responseEntity = response.getEntity();
        //7.解析内容为字符串  读取完毕后会将流关闭
        String string = EntityUtils.toString(responseEntity,"utf-8");
        //8.释放资源
        httpClient.close();
    }

五: 简单发送无参数POST`请求

	@Test
    public void test1() throws Exception {
        //1.创建HTTP请求客户端
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //2.创建发送post请求对象
        HttpPost httpPost = new HttpPost("http://localhost:8080/byte");
        //请求配置使用默认
        httpPost.setConfig(RequestConfig.DEFAULT);
        //3.执行请求, 获取响应对象response
        CloseableHttpResponse response = httpClient.execute(httpPost);
        //4.获取响应内容实体
        HttpEntity responseEntity = response.getEntity();
        //5.解析内容为字符串  读取完毕后会将流关闭
        String string = EntityUtils.toString(responseEntity,"utf-8");
        //6.释放资源
        httpClient.close();
    }

六: 转码为String类型发送POST请求来传输文件

	@Test
    public void test1() throws Exception {
        //1.创建HTTP请求客户端
        HttpClient httpClient = HttpsUtils.getSSLHttpClient();
        //2.创建发送post请求对象
        HttpPost HttpPost = new HttpPost("http://localhost:8080/byte");
        //3.设置请求配置
        HttpPost.setConfig(HttpsUtils.getRequestConfig());
        //将读取文件方法返回的字节数组编码为字符串
        String encode = Base64.getEncoder().encodeToString(this.test02());
        //4.添加请求参数实体
        LinkedList<NameValuePair> parameters = new LinkedList<>();
        parameters.add(new BasicNameValuePair("file",encode));
        parameters.add(new BasicNameValuePair("fileName","张韶涵.jpg"));
        HttpPost.setEntity(new UrlEncodedFormEntity(parameters,"utf-8"));
        //5.执行请求, 获取响应对象response
        HttpResponse response = httpClient.execute(HttpPost);
        //6.获取响应内容实体
        HttpEntity responseEntity = response.getEntity();
        //7.解析内容为字符串  读取完毕后会将流关闭
        String string = EntityUtils.toString(responseEntity,"utf-8");
    }

    /**
     *  读取本地文件通过字节输出流转换成字节数组
     *
     * @return byte[]
     * @author: zhihao
     * @date: 27/2/2020
     */
    public byte[] test02() throws Exception {
        BufferedInputStream is = new BufferedInputStream(new FileInputStream("D:\\admin\\4.jpg"));
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024*2];
        int len = 0;
        while ((len =  is.read(bytes) ) != -1) {
            outputStream.write(bytes,0,len);
        }
        outputStream.close();
        byte[] resultByte = outputStream.toByteArray();
        return resultByte;
    }



//----------------------------------其他后端控制层------------------------------------------
	@PostMapping("/byte")
    public void test03(HttpServletRequest request) {
        BufferedOutputStream os = null;
        try {
            //从参数获取文件名与文件字符串
            String fileName = request.getParameter("fileName");
            String file = request.getParameter("file");
            os = new BufferedOutputStream(new FileOutputStream(new File("D:admin\\123\\" + fileName)));
            //将文件字符串解码为字节数组
            byte[] decode = Base64.getDecoder().decode(file);
            os.write(decode);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IoUtil.close(os);
        }
    }

七: 发送字节数组请求来进行传输文件

		//1.创建HTTP请求客户端
        //2.创建发送post请求对象
        //3.设置请求配置
        //4.添加请求参数实体                    //获取读取文件后的字节输出流的数组
        HttpPost.setEntity(new ByteArrayEntity(this.test02()));
        //文件名通过请求头发送                解决乱码问题
        HttpPost.setHeader("fielName",URLEncoder.encode("66.jpg","utf-8"));
        //5.执行请求, 获取响应对象response
        //6.获取响应内容实体
        //7.解析内容为字符串  读取完毕后会将流关闭

//--------------------------------其他后端控制层--------------------------------------------
	@PostMapping("/byte")
    public void test03(HttpServletRequest request) {
        BufferedOutputStream os = null;
        ServletInputStream is = null;
        try {
            is = request.getInputStream();
            //从请求头获取文件名
            String fileName = URLDecoder.decode(request.getHeader("fielName"),"utf-8");
            os = new BufferedOutputStream(new FileOutputStream(new File("D:\\123\\" + fileName)));
            byte[] bytes = new byte[1024*2];
            int len = 0;
            while ((len = is.read(bytes)) != -1) {
                os.write(bytes,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IoUtil.close(os);
            IoUtil.close(is);
        }
    }

八:其他请求方式省略中…

进行抽取get与post请求的工具类:

import org.apache.http.*;
import org.apache.http.client.HttpClient;
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.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
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.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * @Author: zhihao
 * @Date: 29/2/2020 下午 3:58
 * @Description: HTTP请求工具类 (http走的是默认Http客户端,https走的是SSL协议)
 * @Versions 1.0
 **/
public class HttpsUtils {

    //连接池管理器
    private static PoolingHttpClientConnectionManager connMgr;
    //请求配置
    private static RequestConfig requestConfig;
    //http请求重试处理程序
    private static HttpRequestRetryHandler httpRequestRetryHandler;
    //http客户端
    private static HttpClient httpClient;
    //最大超时时间
    private static final int MAX_TIMEOUT = 10000;
    //cookie存储,可选
    private static BasicCookieStore basicCookieStore = new BasicCookieStore();

    private static final Logger log = LoggerFactory.getLogger(HttpsUtils.class);

    private HttpsUtils() {}

    static {
        //初始化
        init();
    }

    /**
     * 发送 GET请求,不带参数
     *
     * @param url 地址
     * @return java.lang.String 结果字符串,自行json解析
     */
    public static String sendGetRequest(String url) {
        return sendGetRequest(url, new HashMap<String, Object>());
    }

    /**
     * 发送GET带参数请求 ,K-V形式
     *
     * @param url
     * @param params
     * @return java.lang.String 结果字符串,自行json解析
     */
    public static String sendGetRequest(String url, Map<String, Object> params) {
        StringBuffer param = new StringBuffer();
        //先添加请求链接
        param.append(url);
        int i = 0;
        for (String key : params.keySet()) {
            if (i == 0) {
                param.append("?");
            } else {
                param.append("&");
            }
            param.append(key).append("=").append(params.get(key));
            i++;
        }
        String resultString = null;
        //如果是发送https请求使用安全ssl构建
        if (param.toString().startsWith("https")) {
            httpClient = getSSLHttpClient();
        } else {
            httpClient = HttpClients.createDefault();
        }
        try {
            HttpGet httpGet = new HttpGet(param.toString());
            httpGet.setConfig(requestConfig);
            HttpResponse response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            resultString = EntityUtils.toString(entity);
        } catch (IOException e) {
            log.error("请求异常: "+getErrorString(e));
        }
        return resultString;
    }




    /**
     * 发送 POST 请求(HTTP),不带输入数据
     *
     * @param apiUrl 地址
     * @return java.lang.String 结果字符串,自行json解析
     * @date: 27/2/2020
     */
    public static String sendPostRequest(String apiUrl) {
        return sendPostRequest(apiUrl, new HashMap<String, Object>());
    }

    /**
     * 发送POST请求,K-V形式 表单形式
     *
     * @param apiUrl API接口URL
     * @param params 参数map
     * @return java.lang.String 结果字符串,自行json解析
     */
    public static String sendPostRequest(String apiUrl, Map<String, Object> params) {
        if (apiUrl.startsWith("https")) {
            httpClient = getSSLHttpClient();
        } else {
            httpClient = HttpClients.createDefault();
        }
        String resultString = null;
        HttpPost httpPost = new HttpPost(apiUrl);
        try {
            httpPost.setConfig(requestConfig);
            //构造请求参数
            List<NameValuePair> pairList = new ArrayList<>(params.size());
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue().toString());
                pairList.add(pair);
            }
            httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8")));
            HttpResponse response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            resultString = EntityUtils.toString(entity, "UTF-8");
        } catch (IOException e) {
            log.error("请求异常: "+getErrorString(e));
        }
        return resultString;
    }

    /**
     * 发送json方式POST请求
     *
     * @param json   json对象
     * @param apiUrl 地址
     * @return java.lang.String 结果字符串,自行json解析
     */
    public static String sendJsonPostRequest(String apiUrl, Object json) {
        if (apiUrl.startsWith("https")) {
            httpClient = getSSLHttpClient();
        } else {
            httpClient = HttpClients.createDefault();
        }
        String resultString = null;
        HttpPost httpPost = new HttpPost(apiUrl);
        try {
            httpPost.setConfig(requestConfig);
            StringEntity stringEntity = new StringEntity(json.toString(), "UTF-8");// 解决中文乱码问题
            //json请求
            httpPost.addHeader("content-type", "application/json;charset=UTF-8");
            httpPost.setEntity(stringEntity);
            HttpResponse response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            resultString = EntityUtils.toString(entity, "UTF-8");
        } catch (IOException e) {
            log.error("请求异常: "+getErrorString(e));
        }
        return resultString;
    }

    /**
     * <p>
     *      获取HttpClient客户端进行自定义发送请求(例如发送带cookie请求),
     *      注意: 由于使用的是共享的cookie集合, 如果请求过多的不同网站,cookie集合可能会非常大,
     *      并且如果使用过添加cookie方法,那么此工具类获取的getSSLHttpClient请求都会带上所有cookie发送,
     *      并由于配置了DefaultCookieStore(默认cookie存储),
     *      所有getSSLHttpClient请求都会带上响应的cookie进行下一次请求!
     * </p>
     *
     * @param
     * @return org.apache.http.client.HttpClient
     * @author: zhihao
     * @date: 29/2/2020
     * {@link #}
     */
    public static HttpClient getSSLHttpClient() {
//        basicCookieStore = new BasicCookieStore(); //每次请求都是新的cookie
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(createSSLConnSocketFactory())
                .setConnectionManager(connMgr)
                .setDefaultRequestConfig(requestConfig)
                .setRetryHandler(httpRequestRetryHandler)
                //可选配置,如不设置下面的添加,获取,清空cookie将无效
                .setDefaultCookieStore(basicCookieStore)
                .build();
        //清理过期的cookie节省资源
        basicCookieStore.clearExpired(new Date());
        return httpClient;
    }

    /**
     * 添加cookie
     *
     * @param domain 域名 例如:发送的请求是 www.baidu.com
     * @param minute 过期时间
     * @param path   cookie范围
     * @param key
     * @param value
     * @return boolean
     * @author: zhihao
     * @date: 29/2/2020
     */
    public static boolean addCookie(String domain, Integer minute,
                                    String path, String key, String value) throws UnsupportedEncodingException {
        //对value进行编码解决中文乱码
        value = URLEncoder.encode(value, "utf-8");
        BasicClientCookie cookie = new BasicClientCookie(key, value);
        cookie.setDomain(domain);
        cookie.setExpiryDate(new Date(System.currentTimeMillis() + 60 * minute * 1000));
        cookie.setPath(path);
        //添加进cookieStore静态变量中 httpClient使用的是静态变量中的cookieStore,修改对象里面的值相当修改httpClient里面的cookieStore
        basicCookieStore.addCookie(cookie);
        return true;
    }

    /**
     * <p>
     *     进行清空cookie
     * </p>
     *
     * @author: zhihao
     * @date: 29/2/2020 DoNotShare
     */
    public static void ClearBasicCookieStore() {
         basicCookieStore.clear();
    }

    /**
     * <p>
     * 获取响应后的cookie
     * 使用在执行发送请求execute()后才能获取响应的cookie值
     * 使用在之前是获取发送cookie的数据
     * </p>
     *
     * @param
     * @return java.util.List<org.apache.http.cookie.Cookie>
     * @author: zhihao
     * @date: 29/2/2020
     */
    public static List<Cookie> getResponseCookie() {
        return basicCookieStore.getCookies();
    }

    /**
     * 获取请求配置
     *
     * @return org.apache.http.client.config.RequestConfig
     * @author: zhihao
     * @date: 27/2/2020
     */
    public static RequestConfig getRequestConfig() {
        return requestConfig;
    }

    /**
     * 创建SSL安全连接
     *
     * @return
     */
    private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
        SSLConnectionSocketFactory sslsf = null;
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                // 信任所有
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();

            sslsf = new SSLConnectionSocketFactory(sslContext, new HostnameVerifier() {
                @Override
                public boolean verify(String arg0, SSLSession arg1) {
                    return true;
                }
            });
        } catch (GeneralSecurityException e) {
            log.error(e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
        return sslsf;
    }

    /**
     * 初始化连接参数
     *
     * @return void
     * @date: 27/2/2020
     */
    private static void init() {
        // 设置连接池
        connMgr = new PoolingHttpClientConnectionManager();
        // 设置连接池大小
        connMgr.setMaxTotal(100);
        connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());
        // Validate connections after 1 sec of inactivity
        connMgr.setValidateAfterInactivity(1000);
        RequestConfig.Builder configBuilder = RequestConfig.custom();
        // 设置连接超时
        configBuilder.setConnectTimeout(MAX_TIMEOUT);
        // 设置读取超时
        configBuilder.setSocketTimeout(MAX_TIMEOUT);
        // 设置从连接池获取连接实例的超时
        configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);
        //设置Cookie规范
        configBuilder.setCookieSpec(CookieSpecs.STANDARD_STRICT);
        requestConfig = configBuilder.build();
        //http请求重试处理程序
        httpRequestRetryHandler = new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException exception,
                                        int executionCount, HttpContext context) {
                // 如果已经重试了3次,就放弃
                if (executionCount >= 3) {
                    log.error("----链接已经重连了3次未能成功,将放弃->>");
                    return false;
                }
                // 如果服务器丢掉了连接,那么就重试
                if (exception instanceof NoHttpResponseException) {
                    return true;
                }
                if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
                    log.error("----不要重试SSL握手异常->>");
                    return false;
                }
                if (exception instanceof InterruptedIOException) {// 超时
                    log.error("----超时异常->>");
                    return false;
                }
                if (exception instanceof UnknownHostException) {// 目标服务器不可达
                    log.error("----目标服务器不可达异常->>");
                    return false;
                }
                if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
                    log.error("----连接被拒绝异常->>");
                    return false;
                }
                if (exception instanceof SSLException) {// SSL握手异常
                    log.error("----SSL握手异常->>");
                    return false;
                }

                HttpClientContext clientContext = HttpClientContext.adapt(context);
                HttpRequest request = clientContext.getRequest();

                if (!(request instanceof HttpEntityEnclosingRequest)) {
                    return true;
                }
                return false;
            }
        };
    }

    /**
     *  将异常转换为字符串
     *
     * @param e 异常
     * @return java.lang.String
     * @author: zhihao
     * @date: 1/3/2020
     */
    private static String getErrorString(Throwable e) {
        if (null == e){
            return null;
        }
        StringBuilder builder = new StringBuilder();
        builder.append(e.getMessage());
        StackTraceElement[] stackTrace = e.getStackTrace();
        for (StackTraceElement traceElement : stackTrace) {
            builder.append("\n");
            builder.append(traceElement.toString());
        }
        return builder.toString();
    }
}

扩展资料:

Request请求对象不会继承客户端级别的请求配置,所以在自定义Request的时候,需要将客户端的默认配置设置过去:HttpPost.setConfig(HttpsUtils.getRequestConfig());

-----------------------------------------------------------------------------

备忘录:

获取响应状态码: response.getStatusLine().getStatusCode()

获取响应流: InputStream inputStream = response.getEntity().getContent();

禁止过多无用的日记信息:

如果未安装Log4j库,则HttpClient(以及JWebUnit)将使用logback。 在这种情况下,创建或编辑logback.xml以包括:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <!-- 定义有颜色的日记输出格式   -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger) --- %cyan(%msg%n)"/>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!--    包括下面3个-->
    <logger name="org.apache" level="ERROR"/>
    <logger name="org.apache.http.wire" level="ERROR"/>
    <logger name="org.apache.http.headers" level="ERROR"/>
    <root level="info">
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

懵懵懂懂程序员

如果节省了你的时间, 请鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值