zoukankan      html  css  js  c++  java
  • HttpClient

    知识概述

    HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。

    HttpClient的主要功能:

    • 实现了所有 HTTP 的方法(GET、POST、PUT、HEAD、DELETE、HEAD、OPTIONS 等)
    • 支持 HTTPS 协议
    • 支持代理服务器(Nginx等)等
    • 支持自动(跳转)转向

    HttpClient入门案例

    1.添加httpClient jar包

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

         2.实现类

    public class TestHttpClient {
        
        /**
         * 1.实例化httpClient对象
         * 2.准备url请求地址  https://www.baidu.com/
         * 3.封装请求方式对象   GET/POST/PUT/DELETE
         * 4.发起http请求.获取服务器响应.
         * 5.判断返回值状态码信息 200.
         * 6.从响应对象中获取服务器返回值数据.
         * @throws IOException 
         * @throws ClientProtocolException 
         */
        
    @Test
        public void testGet() throws ClientProtocolException, IOException {
            CloseableHttpClient client = 
                                HttpClients.createDefault();
            String url = "https://www.baidu.com";
            HttpGet get = new HttpGet(url);
            CloseableHttpResponse response = 
                                client.execute(get);
            if(response.getStatusLine().getStatusCode() == 200) {
                //表示请求服务正确
                HttpEntity entity = response.getEntity();//返回值实体对象
                String result = 
                        EntityUtils.toString(entity, "UTF-8");
                System.out.println(result);
            }
        }
        
    }

    GET无参

    HttpClient发送示例:

    @Test
    public void doGetTestOne() {
            // 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的)
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            // 创建Get请求
            HttpGet httpGet = new HttpGet("http://localhost:12345/doGetControllerOne");
     
            // 响应模型
            CloseableHttpResponse response = null;
            try {
                // 由客户端执行(发送)Get请求
                response = httpClient.execute(httpGet);
                // 从响应模型中获取响应实体
                HttpEntity responseEntity = response.getEntity();
                System.out.println("响应状态为:" + response.getStatusLine());
                if (responseEntity != null) {
                    System.out.println("响应内容长度为:" + responseEntity.getContentLength());
                    System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
                }
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (ParseException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    // 释放资源
                    if (httpClient != null) {
                        httpClient.close();
                    }
                    if (response != null) {
                        response.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

     对应接收示例:

    GET有参(方式一:直接拼接URL):

    HttpClient发送示例:

    /**
         * GET---有参测试 (方式一:手动在url后面加上参数)
         *
         * @date 2018年7月13日 下午4:19:23
         */
        @Test
        public void doGetTestWayOne() {
            // 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的)
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
     
            // 参数
            StringBuffer params = new StringBuffer();
            try {
                // 字符数据最好encoding以下;这样一来,某些特殊字符才能传过去(如:某人的名字就是“&”,不encoding的话,传不过去)
                params.append("name=" + URLEncoder.encode("&", "utf-8"));
                params.append("&");
                params.append("age=24");
            } catch (UnsupportedEncodingException e1) {
                e1.printStackTrace();
            }
     
            // 创建Get请求
            HttpGet httpGet = new HttpGet("http://localhost:12345/doGetControllerTwo" + "?" + params);
            // 响应模型
            CloseableHttpResponse response = null;
            try {
                // 配置信息
                RequestConfig requestConfig = RequestConfig.custom()
                        // 设置连接超时时间(单位毫秒)
                        .setConnectTimeout(5000)
                        // 设置请求超时时间(单位毫秒)
                        .setConnectionRequestTimeout(5000)
                        // socket读写超时时间(单位毫秒)
                        .setSocketTimeout(5000)
                        // 设置是否允许重定向(默认为true)
                        .setRedirectsEnabled(true).build();
     
                // 将上面的配置信息 运用到这个Get请求里
                httpGet.setConfig(requestConfig);
     
                // 由客户端执行(发送)Get请求
                response = httpClient.execute(httpGet);
     
                // 从响应模型中获取响应实体
                HttpEntity responseEntity = response.getEntity();
                System.out.println("响应状态为:" + response.getStatusLine());
                if (responseEntity != null) {
                    System.out.println("响应内容长度为:" + responseEntity.getContentLength());
                    System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
                }
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (ParseException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    // 释放资源
                    if (httpClient != null) {
                        httpClient.close();
                    }
                    if (response != null) {
                        response.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

     对应接收实例:

    POST有参(普通参数):

    注:POST传递普通参数时,方式与GET一样即可,这里以直接在url后缀上参数的方式示例。

    HttpClient发送示例:

    @Test
        public void doPostTestFour() {
     
            // 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的)
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
     
            // 参数
            StringBuffer params = new StringBuffer();
            try {
                // 字符数据最好encoding以下;这样一来,某些特殊字符才能传过去(如:某人的名字就是“&”,不encoding的话,传不过去)
                params.append("name=" + URLEncoder.encode("&", "utf-8"));
                params.append("&");
                params.append("age=24");
            } catch (UnsupportedEncodingException e1) {
                e1.printStackTrace();
            }
     
            // 创建Post请求
            HttpPost httpPost = new HttpPost("http://localhost:12345/doPostControllerFour" + "?" + params);
     
            // 设置ContentType(注:如果只是传普通参数的话,ContentType不一定非要用application/json)
            httpPost.setHeader("Content-Type", "application/json;charset=utf8");
     
            // 响应模型
            CloseableHttpResponse response = null;
            try {
                // 由客户端执行(发送)Post请求
                response = httpClient.execute(httpPost);
                // 从响应模型中获取响应实体
                HttpEntity responseEntity = response.getEntity();
     
                System.out.println("响应状态为:" + response.getStatusLine());
                if (responseEntity != null) {
                    System.out.println("响应内容长度为:" + responseEntity.getContentLength());
                    System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
                }
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (ParseException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    // 释放资源
                    if (httpClient != null) {
                        httpClient.close();
                    }
                    if (response != null) {
                        response.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    对应接收示例:

       Spring整合HttpClient

    1.编辑pro配置文件

    #最大连接数
    http.maxTotal = 1000
    #并发数
    http.defaultMaxPerRoute = 20
    #创建连接的最长时间
    http.connectTimeout=5000
    #从连接池中获取到连接的最长时间
    http.connectionRequestTimeout=500
    #数据传输的最长时间
    http.socketTimeout=5000
    #提交请求前测试连接是否可用
    http.staleConnectionCheckEnabled=true

    2.编辑配置类

    package com.jt.config;
    
    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();
        }
    }

    3. 编辑关闭连接配置文件

    package com.jt.config;
    
    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(); //全部从等待中唤醒.执行关闭操作;
            }
        }
    }

    5. 编辑工具API

    package com.jt.util;
    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.http.HttpEntity;
    import org.apache.http.NameValuePair;
    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?key1=value1&key2=value2...
         * @param url
         * @param params
         * @param charset
         * @return
         */
        public String doGet(String url,Map<String,String> params,String charset) {
            //1.校验用户是否传递字符编码
            if(StringUtils.isEmpty(charset)) {
                
                charset = "UTF-8";
            }
            
            //2.封装URL地址
            //  http://www.baidu.com?key1=value1&key2=value2&...
            if(params != null) {
                url = url + "?";
                //map遍历
                for (Map.Entry<String,String> entry : params.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    url += key+"="+value+"&";
                }
                //截去多余的&
                url = url.substring(0, url.length()-1);
            }
            
            //3.定义httpGet请求对象
            HttpGet httpGet = new HttpGet(url);
            //设定请求的超时时间
            httpGet.setConfig(requestConfig);
            
            //定义返回值数据
            String result = null;
            try {
                CloseableHttpResponse response = httpClient.execute(httpGet);
                if(response.getStatusLine().getStatusCode() == 200) {
                    //表示请求正确
                    HttpEntity entity = response.getEntity();
                    result = EntityUtils.toString(entity,charset);
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
            
            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);
        }
        
        
        
        //实现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);
        }
    }

    6.编辑测试类调试程序

    @Autowired
        private HttpClientService httpClient;
        
        @Test
        public void doGet() {
            //http://manage.jt.com/web/item/findItemById?itemId=1474391969
            String url = 
            "http://manage.jt.com/web/item/findItemById";
            Map<String,String> params = new HashMap<>();
            params.put("itemId", "562379");
            String json = httpClient.doGet(url, params);
            System.out.println(json);
        }

    HttpClient调用过程

  • 相关阅读:
    js-事件总结
    iquery-个人总结
    CSS3-页面样式
    野生码农狂奔中的2014年度年终总结
    算不算被虚度的这几年
    在Ubuntu 12.4 下安装 nginx, MySQL, PHP
    使用WP8最新的AudioVideoCaptureDevice类制作录像应用
    WP8 MediaElement 实现循环播放
    WPF(WP7、WP8)多个Listbox嵌套时滚动问题的解决
    Weibo SDK WP版本回调参数没有uid的解决方法
  • 原文地址:https://www.cnblogs.com/ming-long/p/11844898.html
Copyright © 2011-2022 走看看