zoukankan      html  css  js  c++  java
  • HttpClient实现跨域请求

       HttpClient实现跨域请求,我们也可以理解为不同系统间的接口调用,那么什么为跨域呢?可以总结为不同域名,不同端口或者相同域名不同端口的系统。分布式项目是现在市场的主流,跨域请求在项目中各子系统中的联系也是必不可少。熟悉的跨域请求技术一个jsonp,一个HttpClient,jsonp底层是通过<script>调用回调函数并传递参数实现跨域,但他只能实现get请求,有时间整理出来再与大家分享。废话不多说,下面一起探讨HttpClient。

       HttpClient其主要作用就是通过Http协议,向某个URL地址发起请求,并且获取响应结果,我们通过一个简单的案例就可以快速入门

    1.1发起Get请求

    public class DoGET {
    
     
    
        public static void main(String[] args) throws Exception {
    
            // 创建Httpclient对象,相当于打开了浏览器
    
            CloseableHttpClient httpclient = HttpClients.createDefault();
    
     
    
            // 创建HttpGet请求,相当于在浏览器输入地址
    
            HttpGet httpGet = new HttpGet("http://www.baidu.com/");
    
     
    
            CloseableHttpResponse response = null;
    
            try {
    
                // 执行请求,相当于敲完地址后按下回车。获取响应
    
                response = httpclient.execute(httpGet);
    
                // 判断返回状态是否为200
    
                if (response.getStatusLine().getStatusCode() == 200) {
    
                    // 解析响应,获取数据
    
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
    
                    System.out.println(content);
    
                }
    
            } finally {
    
                if (response != null) {
    
                    // 关闭资源
    
                    response.close();
    
                }
    
                // 关闭浏览器
    
                httpclient.close();
    
            }
    
     
    
        }
    
    }


    1.2带参数的get请求

    public class DoGETParam {
    
     
    
        public static void main(String[] args) throws Exception {
    
            // 创建Httpclient对象
    
            CloseableHttpClient httpclient = HttpClients.createDefault();
    
            // 创建URI对象,并且设置请求参数
    
            URI uri = new URIBuilder("http://www.baidu.com/s").setParameter("wd", "java").build();
    
            // 创建http GET请求
    
            HttpGet httpGet = new HttpGet(uri);
    
     
    
            CloseableHttpResponse response = null;
    
            try {
    
                // 执行请求
    
                response = httpclient.execute(httpGet);
    
                // 判断返回状态是否为200
    
                if (response.getStatusLine().getStatusCode() == 200) {
    
                    // 解析响应数据
    
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
    
                    System.out.println(content);
    
                }
    
            } finally {
    
                if (response != null) {
    
                    response.close();
    
                }
    
                httpclient.close();
    
            }
    
        }
    
    }


    1.3发起post请求

    public class DoPOST {
    
        public static void main(String[] args) throws Exception {
    
            // 创建Httpclient对象
    
            CloseableHttpClient httpclient = HttpClients.createDefault();
    
            // 创建http POST请求
    
            HttpPost httpPost = new HttpPost("http://www.oschina.net/");
    
            // 把自己伪装成浏览器。否则开源中国会拦截访问
    
            httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
    
     
    
            CloseableHttpResponse response = null;
    
            try {
    
                // 执行请求
    
                response = httpclient.execute(httpPost);
    
                // 判断返回状态是否为200
    
                if (response.getStatusLine().getStatusCode() == 200) {
    
                    // 解析响应数据
    
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
    
                    System.out.println(content);
    
                }
    
            } finally {
    
                if (response != null) {
    
                    response.close();
    
                }
    
                // 关闭浏览器
    
                httpclient.close();
    
            }
    
     
    
        }
    
    }


    1.4带参数post请求

    public class DoPOSTParam {
    
     
    
        public static void main(String[] args) throws Exception {
    
            // 创建Httpclient对象
    
            CloseableHttpClient httpclient = HttpClients.createDefault();
    
            // 创建http POST请求,访问开源中国
    
            HttpPost httpPost = new HttpPost("http://www.oschina.net/search");
    
     
    
            // 根据开源中国的请求需要,设置post请求参数
    
            List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
    
            parameters.add(new BasicNameValuePair("scope", "project"));
    
            parameters.add(new BasicNameValuePair("q", "java"));
    
            parameters.add(new BasicNameValuePair("fromerr", "8bDnUWwC"));
    
            // 构造一个form表单式的实体
    
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);
    
            // 将请求实体设置到httpPost对象中
    
            httpPost.setEntity(formEntity);
    
     
    
            CloseableHttpResponse response = null;
    
            try {
    
                // 执行请求
    
                response = httpclient.execute(httpPost);
    
                // 判断返回状态是否为200
    
                if (response.getStatusLine().getStatusCode() == 200) {
    
                    // 解析响应体
    
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
    
                    System.out.println(content);
    
                }
    
            } finally {
    
                if (response != null) {
    
                    response.close();
    
                }
    
                // 关闭浏览器
    
                httpclient.close();
    
            }
    
        }
    
    }

    2.5使用连接池管理器

    public class HttpConnectManager {
    
     
    
        public static void main(String[] args) throws Exception {
    
            // 构建连接池管理器对象
    
            PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
    
            // 设置最大连接数
    
            cm.setMaxTotal(200);
    
            // 设置每个主机地址的并发数
    
            cm.setDefaultMaxPerRoute(20);
    
     
    
            // 构建请求配置信息
    
            RequestConfig config = RequestConfig.custom().setConnectTimeout(1000) // 创建连接的最长时间
    
                    .setConnectionRequestTimeout(500) // 从连接池中获取到连接的最长时间
    
                    .setSocketTimeout(10 * 1000) // 数据传输的最长时间
    
                    .setStaleConnectionCheckEnabled(true) // 提交请求前测试连接是否可用
    
                    .build();
    
     
    
            // 构建HttpClient对象,把连接池、请求配置对象作为参数
    
            CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm)
    
                    .setDefaultRequestConfig(config).build();
    
     
    
            doGet(httpClient);
    
            doGet(httpClient);
    
        }
    
     
    
        public static void doGet(CloseableHttpClient httpClient) throws Exception {
    
            // 创建http GET请求
    
            HttpGet httpGet = new HttpGet("http://www.baidu.com/");
    
     
    
            CloseableHttpResponse response = null;
    
            try {
    
                // 执行请求
    
                response = httpClient.execute(httpGet);
    
                // 判断返回状态是否为200
    
                if (response.getStatusLine().getStatusCode() == 200) {
    
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
    
                    System.out.println("内容长度:" + content.length());
    
                }
    
            } finally {
    
                if (response != null) {
    
                    response.close();
    
                }
    
                // 此处不能关闭httpClient,如果关闭httpClient,连接池也会销毁
    
                // httpClient.close();
    
            }
    
        }
    
    }


    注意:

    1) 在案例中的配置相当重要,特别是各种有关超时时间的配置。如果不配置1,可能就会导致坏连接一直阻塞,影响其它请     求。或者导致无法获取结果,产生意想不到的错误。

    2) HttpClient对象不要关闭,否则会导致整个连接池失效。

    实际开发中,HttpClient虽然有连接池来管理连接。但是,如果访问的服务端已经断开了连接,作为客户端的HttpClient是不知道的。此时,池中的这个连接就是一个无效的连接。如果这样的连接很多,就会造成有效连接数的减少,服务器的压力变大,直至崩溃。因此,定期清理无效的链接显得尤为重要。

    定期清理无效链接

    public class ClientEvictExpiredConnections {
    
     
    
        public static void main(String[] args) throws Exception {
    
            PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
    
            // 设置最大连接数
    
            cm.setMaxTotal(200);
    
            // 设置每个主机地址的并发数
    
            cm.setDefaultMaxPerRoute(20);
    
            // 开启线程,执行清理链接的任务
    
            new IdleConnectionEvictor(cm).start();
    
        }
    
        // 创建内部类,继承Thread,成为线程类
    
        public static class IdleConnectionEvictor extends Thread {
    
     
    
            private final HttpClientConnectionManager connMgr;
    
     
    
            private volatile boolean shutdown;
    
     
    
            public IdleConnectionEvictor(HttpClientConnectionManager connMgr) {
    
                this.connMgr = connMgr;
    
            }
    
            // 定义线程任务,定时关闭失效的连接
    
            @Override
    
            public void run() {
    
                try {
    
                    while (!shutdown) {
    
                        synchronized (this) {
    
                            // 每隔5秒钟一次
    
                            wait(5000);
    
                            // 关闭失效的连接
    
                            connMgr.closeExpiredConnections();
    
                        }
    
                    }
    
                } catch (InterruptedException ex) {
    
                    // 结束
    
                }
    
            }
    
     
    
            public void shutdown() {
    
                shutdown = true;
    
                synchronized (this) {
    
                    notifyAll();
    
                }
    
            }
    
        }
    
    }


    SSM中整合HttpClient

    要在项目中整合HttpClient,其实就是把HttpClient注册到Spring容器中。

    而一般注册一个Bean,也有两种方式:XML配置或者注解。

    我们选哪种?
    方式1,XML配置

    l 新建applicationContext-httpClient.xml文件:

    l 编写配置

    <beans xmlns="http://www.springframework.org/schema/beans"
    
    xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
    
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
    
     
    
    <!-- 配置连接池管理器 -->
    
    <bean id="httpClientConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager">
    
    <!-- 配置最大连接数 -->
    
    <property name="maxTotal" value="${http.maxTotal}" />
    
    <!-- 配置每个主机地址的最大连接数 -->
    
    <property name="defaultMaxPerRoute" value="${http.defaultMaxPerRoute}" />
    
    </bean>
    
    <!-- 配置RequestConfigBuilder -->
    
    <bean id="requestConfigBuilder" class="org.apache.http.client.config.RequestConfig.Builder">
    
             <!-- 创建连接的最长时间 -->
    
             <property name="connectTimeout" value="${http.connectTimeout}" />
    
             <!-- 从连接池中获取到连接的最长时间 -->
    
             <property name="connectionRequestTimeout" value="${http.connectionRequestTimeout}" />
    
             <!-- 数据传输的最长时间 -->
    
             <property name="socketTimeout" value="${http.socketTimeout}" />
    
             <!-- 提交请求前测试连接是否可用 -->
    
             <property name="staleConnectionCheckEnabled" value="${http.staleConnectionCheckEnabled}" />
    
    </bean>
    
    <!-- 配置RequestConfig -->
    
    <bean id="requestConfig" factory-bean="requestConfigBuilder" factory-method="build"/>
    
    <!-- 配置HttpClientBuilder -->
    
    <bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder">
    
    <!-- 注入连接池管理器 -->
    
    <property name="connectionManager" ref="httpClientConnectionManager" />
    
    <!-- 注入默认的请求配置对象 -->
    
    <property name="defaultRequestConfig" ref="requestConfig" />
    
    </bean>
    
     
    
    <!-- 配置HttpClient -->
    
    <bean factory-bean="httpClientBuilder" factory-method="build"></bean>
    
    </beans>


    注意,在上面的配置中,引用了${},外部属性文件。所以,在Spring的核心配置中添加配置文件:appliationContext.xml中

    l httpClient.properties :资源文件放在项目的根目录下 resource

    l 定义一个HttpClient的通用Service:提供get请求和POST请求的方法

    @Service
    
    public class XmlApiService {
    
        // 注入在XML中已经配置好的HttpClient对象
    
        @Autowired
    
        private CloseableHttpClient httpClient;
    
        
    
        /**
    
         * 无参的get请求
    
         */
    
        public String doGet(String uri) throws IOException {
    
            // 创建HttpGet请求,相当于在浏览器输入地址
    
            HttpGet httpGet = new HttpGet(uri);
    
     
    
            CloseableHttpResponse response = null;
    
            try {
    
                // 执行请求,相当于敲完地址后按下回车。获取响应
    
                response = httpClient.execute(httpGet);
    
                // 判断返回状态是否为200
    
                if (response.getStatusLine().getStatusCode() == 200) {
    
                    // 解析响应,获取数据
    
                    return EntityUtils.toString(response.getEntity(), "UTF-8");
    
                }
    
            } finally {
    
                if (response != null) {
    
                    response.close();
    
                }
    
            }
    
            return null;
    
        }
    
     
    
        /**
    
         * 有参get请求
    
         */
    
        public String doGet(String uri, Map<String, String> params) throws Exception {
    
            // 创建地址构建器
    
            URIBuilder builder = new URIBuilder(uri);
    
            // 拼接参数
    
            for (Map.Entry<String, String> me : params.entrySet()) {
    
                builder.addParameter(me.getKey(), me.getValue());
    
            }
    
            return doGet(builder.build().toString());
    
     
    
        }
    
     
    
        /**
    
         * 有参POST请求
    
         */
    
        public String doPost(String uri, Map<String, String> params) throws ParseException, IOException {
    
            // 创建http POST请求
    
            HttpPost httpPost = new HttpPost(uri);
    
            httpPost.setHeader("User-Agent",
    
                    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
    
            if (params != null) {
    
                // 设置参数
    
                List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
    
                for (Map.Entry<String, String> me : params.entrySet()) {
    
                    parameters.add(new BasicNameValuePair(me.getKey(), me.getValue()));
    
                }
    
                // 构造一个form表单式的实体
    
                UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);
    
                // 将请求实体设置到httpPost对象中
    
                httpPost.setEntity(formEntity);
    
            }
    
     
    
            CloseableHttpResponse response = null;
    
            try {
    
                // 执行请求
    
                response = httpClient.execute(httpPost);
    
                // 判断返回状态是否为200
    
                if (response.getStatusLine().getStatusCode() == 200) {
    
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
    
                    System.out.println(content);
    
                }
    
            } finally {
    
                if (response != null) {
    
                    response.close();
    
                }
    
            }
    
            return null;
    
        }
    
     
    
        /**
    
         * 无参POST请求
    
         */
    
        public String doPost(String uri) throws ParseException, IOException {
    
            return doPost(uri, null);
    
        }
    
    }
    
     
    
    l 先把清理无效连接的线程复制到项目中:
    
    注意修改构造函数,在构造函数中启动当前线程任务,这样当Bean一旦注册,线程就启动了
    
    /**
    
     * 定时清理无效链接的线程
    
     */
    
    public class IdleConnectionEvictor extends Thread {
    
     
    
        private final HttpClientConnectionManager connMgr;
    
     
    
        private volatile boolean shutdown;
    
     
    
        public IdleConnectionEvictor(HttpClientConnectionManager connMgr) {
    
            this.connMgr = connMgr;
    
            // 启动线程
    
            this.start();
    
        }
    
     
    
        // 定义线程任务,定时关闭失效的连接
    
        @Override
    
        public void run() {
    
            try {
    
                while (!shutdown) {
    
                    synchronized (this) {
    
                        // 每隔5秒钟一次
    
                        wait(5000);
    
                        // 关闭失效的连接
    
                        connMgr.closeExpiredConnections();
    
                    }
    
                }
    
            } catch (InterruptedException ex) {
    
                // 结束
    
            }
    
            System.out.println("清理任务 即将结束。。");
    
        }
    
     
    
        public void shutdown() {
    
            shutdown = true;
    
            synchronized (this) {
    
                notifyAll();
    
            }
    
        }
    
    }

    l 在applicationContext-httpclient.xml配置文件中注册该类:

    <bean class="com.taotao.common.bean.IdleConnectionEvictor" destroy-method="shutdown">
    
    <constructor-arg index="0" ref="httpClientConnectionManager"></constructor-arg>
    
    </bean>
    
     
    
    l 完整的applicationContext-httpclient.xml:
    
     
    
    <beans xmlns="http://www.springframework.org/schema/beans"
    
    xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
    
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
    
       
    
    <!-- 设置请求参数的配置 -->
    
    <bean id="configBuilder" class="org.apache.http.client.config.RequestConfig.Builder">
    
    <!-- 创建连接的最长时间 -->
    
    <property name="connectTimeout" value="${httpclient.connectTimeout}"></property>
    
    <!-- 从连接池中获取到连接的最长时间 -->
    
    <property name="connectionRequestTimeout" value="${httpclient.connectionRequestTimeout}"></property>
    
    <!-- 数据传输的最长时间 -->
    
    <property name="socketTimeout" value="${httpclient.socketTimeout}"></property>
    
    <!-- 提交请求前测试连接是否可用 -->
    
    <property name="staleConnectionCheckEnabled" value="${httpclient.staleConnectionCheckEnabled}"></property>
    
    </bean>
    
    <!-- 配置RequestConfig -->
    
    <bean  id="requestConfig" factory-bean="configBuilder" factory-method="build"></bean>
    
     <!-- httpclient连接管理器 -->
    
    <bean id="httpClientConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager">
    
    <!-- 最大连接数 -->
    
    <property name="maxTotal" value="${httpclient.maxTotal}"></property>
    
    <!-- 设置每个主机地址的并发数 -->
    
    <property name="defaultMaxPerRoute" value="${httpclient.defaultMaxPerRoute}"></property>
    
    </bean>
    
         <!-- httpclient的构造器 -->
    
    <bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder">
    
    <property name="connectionManager" ref="httpClientConnectionManager"></property>
    
    <!-- 注入默认的请求配置对象 -->
    
    <property name="defaultRequestConfig" ref="requestConfig" />
    
    </bean>
    
        <!-- 配置httpclient对象 scope="prototype" : 默认是单例,我们改成prototype,每次重新创建一个实例-->
    
    <bean class="org.apache.http.impl.client.CloseableHttpClient"
    
     factory-bean="httpClientBuilder" factory-method="build" >
    
     </bean>
    
    <!-- 自定义定期关闭无效HttpClient连接的类 -->
    
    <bean class="com.taotao.common.bean.IdleConnectionEvictor" destroy-method="shutdown">
    
    <constructor-arg index="0" ref="httpClientConnectionManager"></constructor-arg>
    
    </bean>
    
    </beans>


    l 测试

    @RunWith(SpringJUnit4ClassRunner.class)
    
    @ContextConfiguration(locations = "classpath:spring/applicationContext*.xml")
    
    public class ApiServiceTest {
    
     
    
        @Autowired
    
        private XmlApiService apiService;
    
        
    
        @Test
    
        public void testDoGetString() throws IOException {
    
            String content = this.apiService.doGet("http://www.baidu.com");
    
            System.out.println(content);
    
        }
    
     
    
        @Test
    
        public void testDoGetStringMapOfStringString() throws Exception {
    
            Map<String,String> params = new HashMap<>();
    
            params.put("categoryId", "13");
    
            params.put("rows", "6");
    
            params.put("callback", "func");
    
            String content = this.apiService.doGet("http://manage.taotao.com/rest/api/content",params);
    
            System.out.println(content);
    
        }
    
     
    
        @Test
    
        public void testDoPostStringMapOfStringString() throws ParseException, IOException {
    
     
    
            Map<String,String> params = new HashMap<>();
    
            params.put("scope", "project");
    
            params.put("q", "java");
    
            params.put("fromerr", "8bDnUWwC");
    
            
    
            String content = this.apiService.doPost("http://www.oschina.net/search", params);
    
            System.out.println(content);
    
        }
    
     
    
        @Test
    
        public void testDoPostString() {
    
            fail("Not yet implemented");
    
        }
    
     
    
    }


    一切OK,整合成功

    方式2:注解方式

    直接在APIService中,通过@value注解来注入 配置参数。

    然后通过@PostConstructor 注解来声明一个初始化方法,在这个方法中完成HttpClient对象的创建。

    /**
    
     * 通过HttpClient进行远程调用的Service
    
     */
    
    @Service
    
    public class ApiService {
    
     
    
        @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;
    
     
    
        private CloseableHttpClient httpClient;
    
     
    
        // PostConstruct注解标明该方法为初始化方法,会在对象构造函数执行完毕后执行
    
        @PostConstruct
    
        public void init() {
    
            // 构建连接池管理器对象
    
            PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
    
            // 设置最大连接数
    
            cm.setMaxTotal(maxTotal);
    
            // 设置每个主机地址的并发数
    
            cm.setDefaultMaxPerRoute(defaultMaxPerRoute);
    
     
    
            // 构建请求配置信息
    
            RequestConfig config = RequestConfig.custom().setConnectTimeout(connectTimeout) // 创建连接的最长时间
    
                    .setConnectionRequestTimeout(connectionRequestTimeout) // 从连接池中获取到连接的最长时间
    
                    .setSocketTimeout(socketTimeout) // 数据传输的最长时间
    
                    .setStaleConnectionCheckEnabled(staleConnectionCheckEnabled) // 提交请求前测试连接是否可用
    
                    .build();
    
     
    
            // 构建HttpClient对象,把连接池、请求配置对象作为参数
    
            httpClient = HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(config).build();
    
        }
    
     
    
        /**
    
         * 无参的get请求
    
         */
    
        public String doGet(String uri) throws IOException {
    
            // 创建HttpGet请求,相当于在浏览器输入地址
    
            HttpGet httpGet = new HttpGet(uri);
    
     
    
            CloseableHttpResponse response = null;
    
            try {
    
                // 执行请求,相当于敲完地址后按下回车。获取响应
    
                response = httpClient.execute(httpGet);
    
                // 判断返回状态是否为200
    
                if (response.getStatusLine().getStatusCode() == 200) {
    
                    // 解析响应,获取数据
    
                    return EntityUtils.toString(response.getEntity(), "UTF-8");
    
                }
    
            } finally {
    
                if (response != null) {
    
                    response.close();
    
                }
    
            }
    
            return null;
    
        }
    
     
    
        /**
    
         * 有参get请求
    
         */
    
        public String doGet(String uri, Map<String, String> params) throws Exception {
    
            // 创建地址构建器
    
            URIBuilder builder = new URIBuilder(uri);
    
            // 拼接参数
    
            for (Map.Entry<String, String> me : params.entrySet()) {
    
                builder.addParameter(me.getKey(), me.getValue());
    
            }
    
            return doGet(builder.build().toString());
    
     
    
        }
    
     
    
        /**
    
         * 有参POST请求
    
         */
    
        public String doPost(String uri, Map<String, String> params) throws ParseException, IOException {
    
            // 创建http POST请求
    
            HttpPost httpPost = new HttpPost(uri);
    
            httpPost.setHeader("User-Agent",
    
                    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
    
            if (params != null) {
    
                // 设置参数
    
                List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
    
                for (Map.Entry<String, String> me : params.entrySet()) {
    
                    parameters.add(new BasicNameValuePair(me.getKey(), me.getValue()));
    
                }
    
                // 构造一个form表单式的实体
    
                UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);
    
                // 将请求实体设置到httpPost对象中
    
                httpPost.setEntity(formEntity);
    
            }
    
     
    
            CloseableHttpResponse response = null;
    
            try {
    
                // 执行请求
    
                response = httpClient.execute(httpPost);
    
                // 判断返回状态是否为200
    
                if (response.getStatusLine().getStatusCode() == 200) {
    
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
    
                    System.out.println(content);
    
                }
    
            } finally {
    
                if (response != null) {
    
                    response.close();
    
                }
    
            }
    
            return null;
    
        }
    
     
    
        /**
    
         * 无参POST请求
    
         */
    
        public String doPost(String uri) throws ParseException, IOException {
    
            return doPost(uri, null);
    
        }
    
    }
    
     
    
     
    
     
    添加定时清理无效连接的任务
    
     
    
    我们这里按照方式2,也就是注解注入的方式来添加定时清理无效链接的任务。
    
     
    
    l 首先,在ApiService类中,定义内部类,实现 Runnable接口,成为任务类,编写定时清理的线程任务
    
     
    
        // 创建内部类,实现Runnable接口,成为线程任务类
    
        private class IdleConnectionEvictor implements Runnable {
    
     
    
            private final HttpClientConnectionManager connMgr;
    
     
    
            private volatile boolean shutdown;
    
     
    
            public IdleConnectionEvictor(HttpClientConnectionManager connMgr) {
    
                this.connMgr = connMgr;
    
            }
    
     
    
            // 定义线程任务,定时关闭失效的连接
    
            @Override
    
            public void run() {
    
                try {
    
                    while (!shutdown) {
    
                        synchronized (this) {
    
                            // 每隔5秒钟一次
    
                            wait(5000);
    
                            // 关闭失效的连接
    
                            connMgr.closeExpiredConnections();
    
                        }
    
                    }
    
                } catch (InterruptedException ex) {
    
                    // 结束
    
                }
    
            }
    
     
    
            public void shutdown() {
    
                shutdown = true;
    
                synchronized (this) {
    
                    notifyAll();
    
                    System.out.println("定时清理任务即将结束。。");
    
                }
    
            }
    
        }


    l 在初始化方法,init中,HttpClient对象创建完毕后,创建任务,并开启线程执行


    l 定义一个destroy方法,当ApiService被销毁前,结束线程任务


    ————————————————
    版权声明:本文为CSDN博主「Mrherny」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/Mrherny/article/details/80392012

  • 相关阅读:
    PHP四种界定符
    设计模式 单例模式与工厂模式
    PHP include与require的区别
    面向对象 static abstract interface 等知识点
    gogland golang 颜色&字体 colors&font 配置文件
    什么是游戏中的帧同步
    kcp协议详解
    kcp流模式与消息模式对比
    kcp源码走读
    kcp结构体字段含义
  • 原文地址:https://www.cnblogs.com/zhaojiu/p/14977153.html
Copyright © 2011-2022 走看看