httpClient4.3.3ABTH认证+密码访问

这里,跟大家分享一个工具类。使用HTTPClient,访问需要密码的连接时,一般需要一个BATH认证。


package com.lzq;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpException;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.CookieSpecs;
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.client.protocol.ClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lzq.monitor.utils.PropertiesFileUtil;
import com.lzq.monitor.utils.https.DateFormatUtil;

/**
 * httpClient 工具类
 */
@SuppressWarnings("deprecation")
public class HttpClientUtils {

	/**HttpClient客户端连接管理器中,连接池最大连接数*/  
	public static final int HTTPCLIENT_CONN_MANAGER_MAXTOTAL = 1100;
	/**HttpClient客户端连接管理器中,连接池最大连接数*/
	public static final int HTTPCLIENT_CONN_MANAGER_MAXPERROUTE = 100;
	
	private static final Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
	
	/**httpClient客户端*/
	private CloseableHttpClient httpClient = null;
	/**httpContext,可指定认证方式*/
	private BasicHttpContext localContext = null;
	
	/** ip */
	public static final String IP = "192.168.24.33"; 
	/** 端口 */
	private static final int PORT = 438; 
	
	public static void main(String[] args) {
		
		
		try {
			int intPort = 9696;
			URI uriDialing = new URIBuilder()
				.setScheme("http")
				.setHost(IP)
				.setPort(PORT)
				.setPath("/api/v1/port/"+intPort+"/redial").build();
			
			HttpClientUtils httpClientUtils = new HttpClientUtils();
			CloseableHttpResponse response =httpClientUtils.requestProcessorGet(uriDialing);
			
			String content = httpClientUtils.getContent(response);
			int intStatusCode = response.getStatusLine().getStatusCode();  //获取请求行
			if (intStatusCode != HttpStatus.SC_OK) {  //如果不是200,则打印response的body信息
				logger.error(response.toString());
			}else {
				System.out.println(content);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 发送请求
	 * @param port
	 * @return
	 * @throws Exception 
	 */
	public CloseableHttpResponse requestProcessorGet(URI uri) throws Exception {
		
		List<Header> headers = this.getDefaultHeaders(null);   //访问拨号接口的headers
		CloseableHttpResponse response = null;  //访问拨号接口返回的response
		CloseableHttpClient httpClient = null;
		try {
			
			httpClient = this.getHttpClient(uri.getHost(),uri.getPort());
			HttpGet httpGet = new HttpGet(uri);  //拨号接口get请求
			
			// 设置请求头信息
			httpGet.setHeaders(headers.toArray(new Header[0]));
			response = httpClient.execute(httpGet,localContext);
		} catch (URISyntaxException e) {
			logger.error("uri异常", e);
		} catch (ClientProtocolException e) {
			logger.error("协议错误", e);
		} catch (IOException e) {
			logger.error("网络错误", e);
		} catch (Exception e) {
			logger.error("response未正常返回", e);
		}
		return response;
	}
	
	private CloseableHttpClient getHttpClient(String ip,int port) throws Exception{
		
		if (httpClient == null) {
			httpClient = this.proxyClientBuilder(ip,port);
		}
		return httpClient;
	}
	/**
	 * 获取文本内容
	 * */
	public String getContent(CloseableHttpResponse resp) throws Exception {
		
		String content = null;
		try {
			content = EntityUtils.toString(resp.getEntity(),"gbk");
			EntityUtils.consume(resp.getEntity());
		} catch (Exception ex) {
			logger.error("获取内容失败", ex); 
		} finally {
			if (resp != null) {
				resp.close();
			}
		}
		return content;
	}

	/**
	 * 初始化代理客户端
	 * @throws Exception 
	 */
	private CloseableHttpClient proxyClientBuilder(String ip,int port) throws Exception {

		//http连接池
		PoolingHttpClientConnectionManager connManager = this.getHttpPoolManager();
		//userAnent
		String userAgent = "Mozilla/5.0 (Windows NT 6.1, WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36";
		//http请求的配置信息
		RequestConfig requestConfig = this.getReuestConfig(); 
		//cookie
		CookieStore cookieStore = new BasicCookieStore();
		//远程被访问主机
		HttpHost targetHost = new HttpHost(ip, port, "http");
		CredentialsProvider credentialsProvider = this.getCredentialsProvider(targetHost);
		 
		BasicScheme basicAuth = new BasicScheme();
		localContext = new BasicHttpContext();
		localContext.setAttribute("preemptive-auth", basicAuth);

		HttpClientBuilder httpClientBuilder = HttpClients.custom()
				.setConnectionManager(connManager)
				.setUserAgent(userAgent)
				.setDefaultCookieStore(cookieStore)
				.setDefaultRequestConfig(requestConfig)
				.disableRedirectHandling();
		
		if (credentialsProvider!=null) {
			httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
			.addInterceptorFirst(new PreemptiveAuthInterceptor()); // 此处连接器功能与credentialsProvider功能类似,二者可以选其一即可
		}
		CloseableHttpClient client = httpClientBuilder.build();

		return client;
	}

	/**
	 * 获取主机信息
	 * @param targetHost
	 * @return
	 */
	private CredentialsProvider getCredentialsProvider(HttpHost targetHost) {
		
		String strUserName = "abc";   //http请求的用户名
		String strPassword = "pwd";    //http请求的密码

		CredentialsProvider credentialsProvider = null;
		AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort(),AuthScope.ANY_REALM);
		Credentials userNameCredentials = new UsernamePasswordCredentials(strUserName, strPassword);
		
		credentialsProvider = new BasicCredentialsProvider();
		credentialsProvider.setCredentials(authScope,userNameCredentials);
		
		logger.info("<<<<<<<<<<<<<<<<<<<<<<<<<password="+
		userNameCredentials.getPassword()+";userName="+userNameCredentials.getUserPrincipal().getName());

		return credentialsProvider;
	}

	/**
	 * http连接池
	 * @return
	 * @throws Exception
	 */
	private PoolingHttpClientConnectionManager getHttpPoolManager() throws Exception{
		
		Registry<ConnectionSocketFactory> registry = this.sslBuilder();
		PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);
        //设置整个连接池最大连接数 根据自己的场景决定
		connManager.setMaxTotal(HTTPCLIENT_CONN_MANAGER_MAXTOTAL); 
		
		// 将每个路由基础的连接增加
        connManager.setDefaultMaxPerRoute(HTTPCLIENT_CONN_MANAGER_MAXPERROUTE);
        connManager.closeIdleConnections(0, TimeUnit.SECONDS);
        connManager.closeExpiredConnections();
		return connManager;
	}
	
	/**
	 * httpClient连接配置信息
	 * @return
	 */
	private RequestConfig getReuestConfig(){
		
		RequestConfig requestConfig = RequestConfig.custom()
              .setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY)
              .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
              .setSocketTimeout(20000)
              .setConnectTimeout(20000)
              .setConnectionRequestTimeout(20000)
              .setRedirectsEnabled(false)
              .build();
		
		return requestConfig;
	}
	
	/**
	 * http连接器,请求发出前,进行拦截
	 */
	class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
		
		@SuppressWarnings("deprecation")
		@Override
	    public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
	        AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
	        if (authState.getAuthScheme() == null) {
	            AuthScheme authScheme = (AuthScheme) context.getAttribute("preemptive-auth");
	            if (authScheme != null) {
	            	CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
	            	HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
	            	AuthScope authScope = new AuthScope(targetHost.getHostName(),targetHost.getPort(),AuthScope.ANY_REALM);
	                Credentials creds = credsProvider.getCredentials(authScope);
	                if (creds == null) {
	            		String strUserName = PropertiesFileUtil.MONITORINIT.getProperty("httpUserName");   //http请求的用户名
	            		String strPassword = PropertiesFileUtil.MONITORINIT.getProperty("httpPassword"); //http请求的密码
	            		if (StringUtils.isBlank(strUserName) && StringUtils.isBlank(strPassword)) {
	            			logger.info("配置文件中并没有取到:ADSL拨号的用户名、密码"+DateFormatUtil.formatDate(new Date()));
	            		}
	                	Credentials userNameCredentials = new UsernamePasswordCredentials(strUserName, strPassword);
	                	authState.setCredentials(userNameCredentials);
//	                    throw new HttpException("No credentials for preemptive authentication");
	                }else {
	                	authState.setCredentials(creds);
	                	logger.info("<<<<<<<<<<<<<<<<<<<<<<认证信息,拦截器截到不为空!!!!"+DateFormatUtil.formatDate(new Date()));
					}
	                authState.setAuthScheme(authScheme);
	            }
	        }
	    }
	}
	
	/**
	 * 获取固定的请求header
	 * */
	public List<Header> getDefaultHeaders(String referer) {
		
		List<Header> headers = new ArrayList<Header>();
		headers.add(new BasicHeader(HttpHeaders.ACCEPT,"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"));
		headers.add(new BasicHeader(HttpHeaders.ACCEPT_ENCODING, "gzip, deflate, br"));
		headers.add(new BasicHeader(HttpHeaders.ACCEPT_LANGUAGE,"zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3"));
		if (StringUtils.isNotBlank(referer)) {
			headers.add(new BasicHeader(HttpHeaders.REFERER, referer));
		}
		return headers;
	}
	/**
	 * 销毁httpClient
	 * @throws Exception 
	 */
	public void destroyHttpClient() {
		try {
			if (httpClient != null) {
				httpClient.close();
				httpClient = null;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 构建SSLContext
	 * 1.支持https访问
	 * 2.支持https双向证书验证
	 */
	protected Registry<ConnectionSocketFactory> sslBuilder() throws Exception {
		
		SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        }).build();
		X509HostnameVerifier hostnameVerifier = new AllowAllHostnameVerifier();
		Registry<ConnectionSocketFactory> socketFactoryRegistry = null;

			socketFactoryRegistry = RegistryBuilder
					.<ConnectionSocketFactory> create()
					.register("http", PlainConnectionSocketFactory.INSTANCE)
					.register(
							"https",	new SSLConnectionSocketFactory(sslContext,
									hostnameVerifier)).build();
		return socketFactoryRegistry;
	}
}


HttpClient,源代码中,第一次访问时,默认并不带上BATH认证信息,而是走普通的Http请求,访问失败后,HttpClient有重试机制,它会去匹配,最相近的访问方式,然后匹配到BATH认证方式之后,再带上BATH信息访问链接。

这种方式实现也可以达到目的,不过我们可以通知强制HttpClient使用BATH认证进行访问,那么每一次访问,就不需要多一次Http请求了。

HttpClient的使用,还是有一些坑的,不过也给我们提供了更大的便利。这就需要我们根据自己的需要去完善它。



评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值