httpClient4.3.3ABTH认证+密码访问

来源:互联网 发布:淘宝小号账号查询 编辑:程序博客网 时间:2024/06/03 21:31

这里,跟大家分享一个工具类。使用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 blocke.printStackTrace();}}/** * 发送请求 * @param port * @return * @throws Exception  */public CloseableHttpResponse requestProcessorGet(URI uri) throws Exception {List<Header> headers = this.getDefaultHeaders(null);   //访问拨号接口的headersCloseableHttpResponse response = null;  //访问拨号接口返回的responseCloseableHttpClient 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();//userAnentString 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(); //cookieCookieStore 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的使用,还是有一些坑的,不过也给我们提供了更大的便利。这就需要我们根据自己的需要去完善它。



1 0
原创粉丝点击