29.1认识HttpClient

来源:互联网 发布:2016奥运男篮冠军数据 编辑:程序博客网 时间:2024/06/05 22:51

前后台分离时,如何实现前台系统调用后台系统?
这里写图片描述

上图有两种调用方式,下面进行一一解释:

1、 通过js调用(图上蓝色线)

    a)  优点    i.  直接调用,没有java代码中转,调用的路径更短    ii. 节省服务器的带宽    b)  缺点    i.  调用接口时无法添加自己的业务逻辑(如:缓存)    ii. 接口不安全    1.  有些接口只能在内网公开    iii.    Jsonp需要接口的提供方提供支持(存在局限性)

2、 通过后台java调用(图上黄色线)

    a)  优点    i.  安全    ii. 可以添加自己的业务逻辑    iii.    对接口的提供方没有要求,没有局限性    b)  缺点    i.  间接调用接口,使得调用路径变长    1.  不是真正的缺点,添加自己业务逻辑    ii. 占用内网的带宽    1.  发布上线时需要考虑服务器机房的网络带宽

总结:在实际企业开发中,以上2种方式都会使用,往往都是这2种方式结合使用

如何在java中发起http请求? – HttpClient

这里写图片描述

创建一个maven项目,在该项目中配置httpclient的标签

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

学习如下几个文件:
这里写图片描述

回想我们使用浏览器的步骤:
1.打开浏览器
2.输入要访问的网址,例如:百度
3.按下回车键,执行我们的请求
4.如果成功就显示页面,该页面是浏览器对html渲染后的效果;如果不成功也会返回给我们一个状态码。
5.使用完成后关闭浏览器

我们在使用httpclient的时候与上述浏览器的使用步骤是一致的。下面贴出详细代码:

DoGET.java

package cn.itcast.httpclient;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.util.EntityUtils;public class DoGET {    public static void main(String[] args) throws Exception {        // 创建Httpclient对象//        打开浏览器        CloseableHttpClient httpclient = HttpClients.createDefault();        // 创建http GET请求//        输入网址        HttpGet httpGet = new HttpGet("http://www.baidu.com/");        CloseableHttpResponse response = null;        try {            // 执行请求//            按下回车键            response = httpclient.execute(httpGet);            // 判断返回状态是否为200            if (response.getStatusLine().getStatusCode() == 200) {//                浏览器度html进行渲染                String content = EntityUtils.toString(response.getEntity(), "UTF-8");                System.out.println("输出内容:"+content);            }        } finally {//            关闭浏览器            if (response != null) {                response.close();            }            httpclient.close();        }    }}

DoGETParam.java

package cn.itcast.httpclient;import java.net.URI;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.utils.URIBuilder;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.util.EntityUtils;public class DoGETParam {    public static void main(String[] args) throws Exception {        // 创建Httpclient对象        CloseableHttpClient httpclient = HttpClients.createDefault();        // 定义请求的参数        URI uri = new URIBuilder("http://www.baidu.com/s").setParameter("wd", "java").build();        System.out.println(uri);        // 创建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();        }    }}

DoPOST.java

(首先测试百度是否可以走post请求)
这里写图片描述
发现报错,说明百度不支持post请求。
换一个连接地址:开源中国http://www.oschina.net/
这里写图片描述
请求成功,说明支持post请求。

编写代码,用程序对该网站做请求:

package cn.itcast.httpclient;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpPost;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.util.EntityUtils;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/");        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();        }    }}

执行该代码发现报403错误,但是刚测试可以进行post请求,这是什么原因呢?是开源做了一个限制,不允许程序访问网站,是为了防止爬虫。解决办法是伪装成浏览器。如何伪装呢?我们发现通过浏览器请求都会加如下信息:
这里写图片描述
我们在程序中加上上述语句即可。

package cn.itcast.httpclient;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpPost;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.util.EntityUtils;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 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 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();        }    }}

DoPOSTParam.java

package cn.itcast.httpclient;import java.util.ArrayList;import java.util.List;import org.apache.http.NameValuePair;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpPost;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.message.BasicNameValuePair;import org.apache.http.util.EntityUtils;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");        // 设置2个post参数,一个是scope、一个是q        List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);        parameters.add(new BasicNameValuePair("scope", "project"));        parameters.add(new BasicNameValuePair("q", "java"));        parameters.add(new BasicNameValuePair("fromerr", "RgI0EeI0"));        // 构造一个form表单式的实体        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);        // 将请求实体设置到httpPost对象中        httpPost.setEntity(formEntity);        httpPost.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 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();        }    }}

上面浏览器中参数的设置依据,都是先用浏览器进行访问,然后按照浏览器的访问格式编写代码用程序去进行访问。
这里写图片描述

以上代码都是先打开浏览器然后访问最后做关闭。每次都创建然后销毁,性能比较差。和数据库的连接有点相像,数据库用的是连接池。这里我们使用连接管理器,来创建浏览器。

package cn.itcast.httpclient;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.conn.HttpClientConnectionManager;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.util.EntityUtils;public class HttpConnectManager {    public static void main(String[] args) throws Exception {        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();        // 设置最大连接数        cm.setMaxTotal(200);        // 设置每个主机地址的并发数        cm.setDefaultMaxPerRoute(20);        doGet(cm);        doGet(cm);    }    public static void doGet(HttpClientConnectionManager cm) throws Exception {//        打开浏览器        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();        // 创建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();        }    }}

上面的连接管理器打开了一个浏览器,可以在该浏览器中执行多个uri,相当于打开一个浏览器里面有多个tab,如下图:
这里写图片描述

如果有些tab页访问过后不再需要,也没有进行关闭的话,就会造成打开的tab越来越多。不可用的tab就会占用资源,就需要我们定期清理无效连接,需要通过一个线程将无效的连接关闭:
ClientEvictExpiredConnections.java

package cn.itcast.httpclient;import org.apache.http.conn.HttpClientConnectionManager;import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;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();    }    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) {                        wait(5000);                        // 关闭失效的连接                        connMgr.closeExpiredConnections();                    }                }            } catch (InterruptedException ex) {                // 结束            }        }        public void shutdown() {            shutdown = true;            synchronized (this) {                notifyAll();            }        }    }}

当我们发起一个http请求的时候都要设置一定的参数,创建连接的最长时间,传输的最长时间等。此处的参数如果不设置会出问题的,比如未设置连接创建时间,就意味着一直连接下去,比如连到一个网站该网站未响应那么我们的程序就会一直去连接,那该程序就一直卡在这里无法继续运行。所以最好还是手动设置一下,可以提高体验性能:
RequestConfigDemo.java

package cn.itcast.httpclient;import org.apache.http.client.config.RequestConfig;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.util.EntityUtils;public class RequestConfigDemo {    public static void main(String[] args) throws Exception {        // 创建Httpclient对象        CloseableHttpClient httpclient = HttpClients.createDefault();        // 创建http GET请求        HttpGet httpGet = new HttpGet("http://www.baidu.com/");        // 构建请求配置信息        RequestConfig config = RequestConfig.custom().setConnectTimeout(1000) // 创建连接的最长时间                .setConnectionRequestTimeout(500) // 从连接池中获取到连接的最长时间                .setSocketTimeout(10 * 1000) // 数据传输的最长时间                .setStaleConnectionCheckEnabled(true) // 提交请求前测试连接是否可用                .build();        // 设置请求配置信息        httpGet.setConfig(config);        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();        }    }}

上面分析了Httpclient中各个文件的作用,下面就把它集成到项目中去使用。我们在程序中肯定使用连接管理器来实现。使用连接管理器,用到的连接池一般都是由spring来管理,下面就需要spring与Httpclient做整合。

原创粉丝点击