文档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();
- }
- }
- }
- }