HttpClient别说话,用心看

文档D:\httpclient-demo

官网:Apache HttpComponents – Apache HttpComponents

常见使用场景:1.爬虫(python相对做爬虫专业,但是java也可以做)  2.与其他应用进行交互时候

注意下,不同的HttpClient的jar包版本,API和包路径有明显不同

先使用JDK原生API请求网页

 将控制台的复制保存为html文件

 双击打开

 request:请求行,请求头,请求体

可以设置请求方式,请求头,等

 依赖

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

演示使用HttpClient发送get请求,无参

@Test
    public void test1(){
        //可关闭的httpclient客户端,相当于打开一个浏览器
        CloseableHttpClient closeableHttpClient=HttpClients.createDefault();
        String str="https://www.baidu.com";
        //构造HttpGet请求对象
        HttpGet httpGet=new HttpGet(str);
        //声明可关闭响应对象
        CloseableHttpResponse response = null;
        try {
            //可关闭的httpclient客户端对象执行httpGet请求
            response=closeableHttpClient.execute(httpGet);
            //获取响应结果 注意HttpEntity有很多实现类,不仅仅可以作为响应结果,还可以作为请求的参数实体
            //作为响应结果的实现类是DecompressingEntity
            HttpEntity httpEntity=response.getEntity();
            //对HttpEntity操作的工具类
            String toStringResult=EntityUtils.toString(httpEntity, StandardCharsets.UTF_8);
            System.out.println(toStringResult);
            //确保流关闭
            EntityUtils.consume(httpEntity);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(response!=null){
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if(closeableHttpClient!=null){
                    try {
                        closeableHttpClient.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

控制台打印结果和原先一样

关于user-agent和referer:

user-agent意思是用户代理:客户端用的什么浏览器

假如一直用Httpclient连接某些网页,如果对方知道你是机器所为

比如下面这样

 可以在请求头里设置user-agent

比如在请求对象里设置:

//构造HttpGet请求对象
HttpGet httpGet=new HttpGet(str);
httpGet.addHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36");

这样一般可以解决httpClient被认为不是真人行为

另外网站为了保护自己,比如爬对方图片,进行防盗链设置

而Referer是用来,解决网站防盗链

每个请求头,都有对应的作用,自己可查看资料

下面演示,一个网站通过浏览器访问后端,后端获取所有请求头,和通过HttpClien发送请求,所得到的请求头有哪些不一样。

该demo一会上传百度云盘

前端就几个表单,做为参数通过get,post,还有文件上传的演示

后端接收,并打印所有由浏览器发起请求的所有请求头

随便用户名,密码,这里输入aaa,密码 bbb 后端得到的所有请求头

且账号密码  都是Okde

 然后再实验 账户aaa,密码aaa+bbb

 

再来看看用HttpClien发送该请求,后端的结果 

也用 aaa  bbb

HttpClient代码  主要注意一点,就是表单提交时候 比如用户名是aaa+bbb的时候,会自动帮我们编码

而如果用HttpClient直接将用户名aaa+bbb  密码xxx这样进行提交的话,后台收到的+号会变空格,甚至说比如空格等特殊符号,直接给你报错了,就是说不让你用HttpClient提交该请求

比如String str=http://localhost:8899/httpclient-demo/test1?userName=aaa  空格  Bbbb&password=bbb

就直接给你报错

 /**
     * 使用httpclient发送get请求
     */
    @Test
    public void test1(){
        //可关闭的httpclient客户端,相当于打开一个浏览器
        CloseableHttpClient closeableHttpClient=HttpClients.createDefault();
        //String str="http://localhost:8899/httpclient-demo/test1?userName=aaa%2Bbbb&password=bbb";
        String str="http://localhost:8899/httpclient-demo/test1?userName="+"aaa+bbb"+"&password=bbb";
        //构造HttpGet请求对象
        HttpGet httpGet=new HttpGet(str);
        httpGet.addHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36");

        //httpGet.addHeader("Referer","http://localhost:8899/httpclient-demo/test1?userName=aaa%2Bbbb&password=bbb");
        //声明可关闭响应对象
        CloseableHttpResponse response = null;
        try {
            //可关闭的httpclient客户端对象执行httpGet请求
            response=closeableHttpClient.execute(httpGet);
            //获取响应结果 注意HttpEntity有很多实现类,不仅仅可以作为响应结果,还可以作为请求的参数实体
            //作为响应结果的实现类是DecompressingEntity
            HttpEntity httpEntity=response.getEntity();
            //对HttpEntity操作的工具类
            String toStringResult=EntityUtils.toString(httpEntity, StandardCharsets.UTF_8);
            System.out.println(toStringResult);
            //确保流关闭
            EntityUtils.consume(httpEntity);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(response!=null){
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if(closeableHttpClient!=null){
                    try {
                        closeableHttpClient.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

报错的演示

想说明的一点是,用浏览器提交表单请求时候,浏览器会帮我们自动对中文和特殊符号进行编码,后端会自行解码,但是当使用HttpClient的时候用注意中文和特殊符号

那么就要将到URLEncode  它可以对RUL上的特殊字符进行编码

用浏览器,提交时候会自动完成URLEncode 而当使用HttpClient时候,中文与特殊符号就需要我们自己使用URLEncode进行编码

丫的CSDN不能上传图片了

就是用URLEncode对get请求进行编码即可

String str="http://localhost:8899/httpclient-demo/test1?userName=   "+"aaa+bbb"+"&password=bbb";
try {
    str=URLEncoder.encode(str, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}

这里注意一点,上面这么做是错的

由于一时没法发图片,这么做的话,会将整个url全部编码,也就是说://  &  ?等等全部进行了编码

而我们只需要对我们上传的参数进行编码,因此正确做法是

lic void test1(){
    //可关闭的httpclient客户端,相当于打开一个浏览器
    CloseableHttpClient closeableHttpClient=HttpClients.createDefault();
    //String str="http://localhost:8899/httpclient-demo/test1?userName=aaa%2Bbbb&password=bbb";
    String userName="aaa 哈哈";
    String password="你妹";
    try {
        //对自定义上传的进行编码
        userName=URLEncoder.encode(userName, StandardCharsets.UTF_8.name());
        password=URLEncoder.encode(password, StandardCharsets.UTF_8.name());
    } catch (Exception e) {
        e.printStackTrace();
    }
    String str="http://localhost:8899/httpclient-demo/test1?+userName="+userName+"&password="+password;

对HttpClient做了些改动,没法发图说明,全复制了一遍

/**
     * 使用httpclient发送get请求
     */
    @Test
    public void test1(){
        //可关闭的httpclient客户端,相当于打开一个浏览器
        CloseableHttpClient closeableHttpClient=HttpClients.createDefault();
        String userName="收到 你没";
        String password="阿斯顿)(";
        try {
            userName= URLEncoder.encode(userName, StandardCharsets.UTF_8.name());
            password=URLEncoder.encode(password, StandardCharsets.UTF_8.name());
        } catch (Exception e) {
            e.printStackTrace();
        }

        String str="http://localhost:8899/httpclient-demo/test1?userName="+userName+"&password="+password;
        //构造HttpGet请求对象
        HttpGet httpGet=new HttpGet(str);
        httpGet.addHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36");
        //httpGet.addHeader("Referer","https://www.amamaw.com");
        //声明可关闭响应对象
        CloseableHttpResponse response = null;
        try {
            //可关闭的httpclient客户端对象执行httpGet请求
            response=closeableHttpClient.execute(httpGet);
            //代表本次请求成功或者失败的状态
            StatusLine statusLine=response.getStatusLine();
            if(HttpStatus.SC_OK==statusLine.getStatusCode()){//HttpStatus里有所有状态码 200 404 302等等
                System.out.println("响应成功");
                //获取所有响应头
                Header[] allHeader=response.getAllHeaders();
                for(Header header:allHeader){
                    System.out.println("响应头:"+header.getName()+":"+header.getValue());
                }

                //成功了再获取响应结果
                //获取响应结果 注意HttpEntity有很多实现类,不仅仅可以作为响应结果,还可以作为请求的参数实体
                //作为响应结果的实现类是DecompressingEntity
                HttpEntity httpEntity=response.getEntity();
                System.out.println("ContentType:"+httpEntity.getContentType());
                //对HttpEntity操作的工具类
                String toStringResult=EntityUtils.toString(httpEntity, StandardCharsets.UTF_8);
                System.out.println(toStringResult);
                //确保流关闭
                EntityUtils.consume(httpEntity);
            }else{
                System.out.println("响应失败,响应码是:"+statusLine.getStatusCode());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(response!=null){
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if(closeableHttpClient!=null){
                    try {
                        closeableHttpClient.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

关于保存网络图片到本地:粗暴点讲就是爬取图片,再写个demo

  @Test
    public void test3(){
        //可关闭的httpclient客户端,相当于打开一个浏览器
        CloseableHttpClient closeableHttpClient=HttpClients.createDefault();
        String userName="收到 你没";
        String password="阿斯顿)(";
        try {
            userName= URLEncoder.encode(userName, StandardCharsets.UTF_8.name());
            password=URLEncoder.encode(password, StandardCharsets.UTF_8.name());
        } catch (Exception e) {
            e.printStackTrace();
        }

        String str="https://img-blog.csdnimg.cn/c2c20ed7275749bba0e43cdf9d66a9d7.png";

        //String str="http://localhost:8899/httpclient-demo/test1?userName="+userName+"&password="+password;
        //构造HttpGet请求对象
        HttpGet httpGet=new HttpGet(str);
        httpGet.addHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36");
        //httpGet.addHeader("Referer","https://www.amamaw.com");
        //声明可关闭响应对象
        CloseableHttpResponse response = null;
        try {
            //可关闭的httpclient客户端对象执行httpGet请求
            response=closeableHttpClient.execute(httpGet);
            //代表本次请求成功或者失败的状态
            StatusLine statusLine=response.getStatusLine();
            if(HttpStatus.SC_OK==statusLine.getStatusCode()){//HttpStatus里有所有状态码 200 404 302等等
                System.out.println("响应成功");
                //获取所有响应头
                Header[] allHeader=response.getAllHeaders();
                for(Header header:allHeader){
                    System.out.println("响应头:"+header.getName()+":"+header.getValue());
                }

                //成功了再获取响应结果
                //获取响应结果 注意HttpEntity有很多实现类,不仅仅可以作为响应结果,还可以作为请求的参数实体
                //作为响应结果的实现类是DecompressingEntity
                HttpEntity httpEntity=response.getEntity();
                //获取图片,一般图片都有后缀,如何保存为原有的后缀 image/jpg image/png image/jpeg image/图片后缀
                String contenType= httpEntity.getContentType().getValue();
                String suffix=".jpg";
                if(contenType.contains("jpg")||contenType.contains("jpeg")){
                    suffix=".jpg";
                }else if(contenType.contains("bmp")||contenType.contains("bitmap")){
                    suffix=".bmp";
                }else if(contenType.contains("png")){
                    suffix=".png";
                }else if(contenType.contains("gif")){
                    suffix=".gif";
                }
                //图片是二进制,toByteArray()可以以流的形式获取任何 文本也可以  图片  视频都行
                byte[] bytes=EntityUtils.toByteArray(httpEntity);
//                String str1=new String(bytes);
//                System.out.println("str1="+str1);
                //定义个本地保存图片的路径
                String localAbsPath="D:\\pachongimage\\"+new SimpleDateFormat("yyyyHHmmhhmmss").format(new Date())+suffix;
                //写入文件
                FileOutputStream fos=new FileOutputStream(localAbsPath);
                fos.write(bytes);
                fos.close();
                System.out.println("ContentType:"+httpEntity.getContentType());
                //对HttpEntity操作的工具类   注意图片是二进制文件,不能再toString()了  只有文本可以
                //String toStringResult=EntityUtils.toString(httpEntity, StandardCharsets.UTF_8);
                //System.out.println(toStringResult);
                //确保流关闭
                EntityUtils.consume(httpEntity);
            }else{
                System.out.println("响应失败,响应码是:"+statusLine.getStatusCode());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(response!=null){
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if(closeableHttpClient!=null){
                    try {
                        closeableHttpClient.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

这样该目录里就有该图片了

设置访问代理,设置访问代理原因,爬虫写多了,高频率访问网站,对方安全性做的比较好的话,会将你IP封掉.那么做爬虫的应对方式就是设置访问代理,用不同IP去访问,请求,避免被封,让它搞不清楚

设置访问代理,有免费的,但是不太稳定,要稳定加钱......

另外再写个Demo

无论HttpGet或者HttpPost都可以配置  这里用HttpGet演示   代理的IP和端口网上找的

//创建一个代理
String ip="120.26.123.95";
int port=8010;
//构造HttpGet请求对象
HttpGet httpGet=new HttpGet(str);
HttpHost proxy=new HttpHost(ip,port);
//对每一个请求进行配置,会覆盖全局的默认请求配置
RequestConfig requestConfig= RequestConfig.custom().setProxy(proxy).build();
httpGet.setConfig(requestConfig);
 /**
     * 演示设置访问代理
     */
    @Test
    public void test4(){
        //可关闭的httpclient客户端,相当于打开一个浏览器
        CloseableHttpClient closeableHttpClient=HttpClients.createDefault();
        String str="http://www.baidu.com";
        //创建一个代理
        String ip="120.26.123.95";
        int port=8010;
        //构造HttpGet请求对象
        HttpGet httpGet=new HttpGet(str);
        HttpHost proxy=new HttpHost(ip,port);
        //对每一个请求进行配置,会覆盖全局的默认请求配置
        RequestConfig requestConfig= RequestConfig.custom().setProxy(proxy).build();
        httpGet.setConfig(requestConfig);
        //声明可关闭响应对象
        CloseableHttpResponse response = null;
        try {
            //可关闭的httpclient客户端对象执行httpGet请求
            response=closeableHttpClient.execute(httpGet);
            //代表本次请求成功或者失败的状态
            StatusLine statusLine=response.getStatusLine();
            if(HttpStatus.SC_OK==statusLine.getStatusCode()){//HttpStatus里有所有状态码 200 404 302等等
                System.out.println("响应成功");
                //获取所有响应头
                Header[] allHeader=response.getAllHeaders();
                for(Header header:allHeader){
                    System.out.println("响应头:"+header.getName()+":"+header.getValue());
                }

                //成功了再获取响应结果
                //获取响应结果 注意HttpEntity有很多实现类,不仅仅可以作为响应结果,还可以作为请求的参数实体
                //作为响应结果的实现类是DecompressingEntity
                HttpEntity httpEntity=response.getEntity();

                System.out.println("ContentType:"+httpEntity.getContentType());
                //对HttpEntity操作的工具类   注意图片是二进制文件,不能再toString()了  只有文本可以
                String toStringResult=EntityUtils.toString(httpEntity, StandardCharsets.UTF_8);
                System.out.println(toStringResult);
                //确保流关闭
                EntityUtils.consume(httpEntity);
            }else{
                System.out.println("响应失败,响应码是:"+statusLine.getStatusCode());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(response!=null){
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if(closeableHttpClient!=null){
                    try {
                        closeableHttpClient.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

关于连接超时,和读取超时的设置与具体含义

关于连接超时,也是通过RequestConfig来进行设置的,这里先把代理去掉

就是设置HTTP三次握手的时间上限,连接超时就报ConnectTimeoutException

//对每一个请求进行配置,会覆盖全局的默认请求配置
RequestConfig requestConfig= RequestConfig.custom().setConnectTimeout(5000).build();
//对每一个请求进行配置,会覆盖全局的默认请求配置
RequestConfig requestConfig= RequestConfig.custom()
        //设置CTP三次握手的时间上线
        .setConnectTimeout(55555)
        //设置从请求的网址获取响应数据的时间渐渐
        .setSocketTimeout(50000)
        //指从连接池获取connection的超时时间
        .setConnectionRequestTimeout(5000)
        .build();
httpGet.setConfig(requestConfig);

接着演示,用HttpClient发送  

Content-Type分别为:

1.application/x-www-form-urlencoded

2.application/json

3multipart/form-data(文件上传时的Content-Type类型)

的Post请求

1.用HttpClient发送content-type为application/x-www-form-urlencoded的post请求

demo送上    注意:content-type为application/x-www-form-urlencoded

他的参数格式是在body体中:KEY1=VALUE1&KEY2=VALUE2的格式

其实下面传送过去的也就是userName=java&password=xxxx的格式

NameValuePair是个接口,BasicNameValuePair是他的一个实现类
/**
     * - 发送application/x-www-form-urlencoded类型的post请求
     *
     * @throws Exception
     */
    @Test
    public void testPost1() throws Exception {
        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
        String urlStr = "http://localhost:8899/httpclient-demo/test2";
        // 创建httppost对象
        HttpPost httpPost = new HttpPost(urlStr);
        // 设置请求头
        httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
        // 给post对象设置参数
        /*
         NameValuePair: <input id="user-name-label" type="text" name="userName"/>
         的name(userName)和input标签里面输入的值就构成了一个NameValuePair对象
         */
        List<NameValuePair> list = new ArrayList<>();
        list.add(new BasicNameValuePair("userName", "java"));
        list.add(new BasicNameValuePair("password", "xxxxx"));
        // 把参数集合设置到formEntity
        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(list, Consts.UTF_8);
        httpPost.setEntity(formEntity);

        CloseableHttpResponse response = null;
        try {
            response = closeableHttpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            String toStringResult = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            System.out.println(toStringResult);
            EntityUtils.consume(entity);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (closeableHttpClient != null) {
                try {
                    closeableHttpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

2.用HttpClient发送content-type为application/json的post请求

在body体中的格式就是JSON

{

        "userName":"java",
        "password":"xxxx",

         "age":18

}

Demo送上

  /**
     * - 发送application/json类型的post请求
     */
    @Test
    public void testPost2() throws Exception {
        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
        String urlStr = "http://localhost:8899/httpclient-demo/testJson";
        // 创建httppost对象
        HttpPost httpPost = new HttpPost(urlStr);

        // string:是一个json字符串
        JSONObject jsonObj = new JSONObject();
        jsonObj.put("userName", "java");
        jsonObj.put("password", "不知道写什么");

        StringEntity jsonEntity = new StringEntity(jsonObj.toString(), Consts.UTF_8);
        // 也需要给entity设置一下内容类型
//        jsonEntity.setContentType(new BasicHeader("Content-Type","application/json; charset=utf-8"));
        jsonEntity.setContentType("application/json; charset=utf-8");
        // 设置entity的编码
        jsonEntity.setContentEncoding(Consts.UTF_8.name());
        httpPost.setEntity(jsonEntity);

        CloseableHttpResponse response = null;
        try {
            response = closeableHttpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            String toStringResult = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            System.out.println(toStringResult);
            EntityUtils.consume(entity);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (closeableHttpClient != null) {
                try {
                    closeableHttpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

hrui0706

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值