HttpClient运用场景

1. HttpClient简介

HttpClient 是 Apache Jakarta Common 下的子项目,是一个用来跨项目访问的中间件 ,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
HttpClient 相比传统 JDK 自带的 URLConnection(URLConnection是一个抽象类,表示指向URL指定资源的活动连接。),增加了易用性和灵活性,它不仅使客户端发送 HTTP 请求变得容易,而且也方便了开发人员测试接口(基于 HTTP 协议的),即提高了开发的效率,也方便提高代码的实用性。

2.HttpClient的运用场景

  1. 网页内容抓取
  2. 模拟登录
  3. 接口调用

一些通过人工操作比较简单,但是比较琐碎的内容,都可以通过系统操作,就能使用httpclient了

3.HttpClient主要功能

  • 实现了所有HTTP的方法(GET、POST、PUT、HEAD、DELETE、HEAD、OPTIONS 等)
  • 支持HTTPS协议
  • 支持代理服务器(NgInx等)等
  • 支持自动(跳转)转向
  • 连接管理器支持多线程应用.(支持设置最大连接数,同时支持设置每个主机的最大连接数,发现并关闭过期的连接。)
  • 设置连接超时的能力。

4.HttpClient使用流程

  1. 创建HttpClient对象.
  2. 创建请求方法的实例,并指定请求URL。如果需要GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。
  3. 如果需要发送请求参数,可以调用HttpGet,HttpPost共同的setParams(HttpParams params)方法来添加请求参数;对于HttpPost对象而言,也可以调用setEntity(HttpEntity entity) 方法来设置请求参数。
  4. 调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。
  5. .调用 HttpResponse 的 getAllHeaders()、getHeaders(String name) 等方法可获取服务器的响应头;调用 HttpResponse 的 getEntity() 方法可获取 HttpEntity 对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
  6. 释放连接。无论执行方法是否成功,都必须释放连接。

5.HTTP请求的GET和POST方式的区别

  1. get是从服务器上获取数据,post是想服务器传送数据。
  2. get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。
  3. 对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务端用Request。Form获取提交的数据。
  4. get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4最大量为80KB,IIS5中为100KB。
  5. get安全性非常低,post安全性较高,但是执行效率却比post方法好。

6.HttpClient方法

6.1:EntityUtils()
在httpclient请求的时候,使用EntityUtils对返回的结果进行字符串的转换。
6.2:getStatusLine().getStatusCode()
获取响应的状态 状态码
6.3 : getEntity()

获取数据 包装了服务器的响应内容
6.4 : setParams(HttpParams params)
添加请求参数。
6.5:setEntity(HttpEntity entity)
设置请求参数。
6.6:execute(HttpUriRequest request)
执行请求。

7.HttpClient使用实例思路

  1. 创建一个httpClient对象实例(可以是从池中获取一个实例)。
  2. 创建一个HttpGet或HttpPost请求,传入指定的url地址。
  3. 调用execute方法调用传入创建的get或post请求。
  4. 执行rxrcute方法,会返回一个HttpResponse实例,里面是返回的数据。
  5. 返回内容和相应结果 200表示访问成功。
  6. 调用getEntity方法获取到一个HttpEntity实例里面是返回的数据。
  7. 调用EntityUtils.toString()将返回的数据进行字符串的转换。
  8. 最后无论无论访问是否成功 都要关流。

引入相关Pom坐标

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

频繁的创建和关闭会影响效率所以这里所引用的是池

httpClient配置文件

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

设置指定的参数

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

关闭连接

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

正常Get-Demo

@Test
	public void testGet() throws ClientProtocolException, Exception
	{
		//Url
		String url = "http://www.baidu.com";
		//Get
		HttpGet get = new HttpGet(url);
		//初始化HttpClient
		HttpClient httpClient = HttpClients.createDefault();
		HttpResponse execute = httpClient.execute(get);
		//获取状态码信息
		if(200==execute.getStatusLine().getStatusCode())
		{
			//转化为字符串 并指定字符集
			String string = EntityUtils.toString(execute.getEntity(),"UTF-8");
			System.out.println(string);
		}
	}

使用池,从池中获取连接

    @Autowired
	private CloseableHttpClient CloseableHttpClient; //从池中获取连接
	@Autowired  
	private RequestConfig requestConfig;  //  控制请求超值时间
	@Test
	public void test01() throws ClientProtocolException, Exception
	{
		String url = "http://manage.jt.com/web/item/findItemById?itemId=562379";
		HttpGet get = new HttpGet(url);
		//传入配置
		get.setConfig(requestConfig);
		HttpResponse execute = CloseableHttpClient.execute(get);
		//获取状态码信息
		if(200==execute.getStatusLine().getStatusCode())
		{
			String string = EntityUtils.toString(execute.getEntity(),"UTF-8");
			System.out.println(string);
		}
	}

开发中封装为一个工具使用

@Autowired
	private CloseableHttpClient HttpClient; //从池中获取连接
	@Autowired  
	private RequestConfig requestConfig;  //  控制请求超值时间
	//封装一下             1.url                 2.参数                            3.字符集
	public String doGet(String url,Map<String, String> params,String charset) 
	{
		//1. 判断字符集编码是否有值.
		if(StringUtils.isEmpty(charset))
			charset = "utf-8"; //没有制定字符编码集,就给utf-8
		//2.判断是否有参数.
		if(params!=null)//有参 ?key=value&key2=value2....
		{
			StringBuffer uri = new StringBuffer();
			uri.append(url).append("?");
			for (Map.Entry<String,String> entity : params.entrySet()) 
			{
				uri.append(entity.getKey())
				.append("=")
				.append(entity.getValue())
				.append("&");
			}
			//去除多余的&号
			url = uri.substring(0, uri.length()-1);
		}
		//3. 定义请求的类型
		HttpGet get = new HttpGet(url);
		get.setConfig(requestConfig);
		//4.发起请求获取结果
		String result = null;
		try {
			CloseableHttpResponse response = HttpClient.execute(get);//发送  get 请求
			if(response.getStatusLine().getStatusCode()==200)//  如果请求状态码正常
				result = EntityUtils.toString(response.getEntity(),charset); // 转换成String JSON串
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException(e);

		}
		return result;
	}

提示:
如果想要自己进行测试,可以配置相关jar包,然后先启动SpringBoot项目,然后在运行相关的test方法,进行测试。

ᕦ(・ㅂ・)ᕤ 如有不当之处,欢迎指正

发布了4 篇原创文章 · 获赞 6 · 访问量 111

猜你喜欢

转载自blog.csdn.net/weixin_45302340/article/details/103585277