package net.dev123.commons.http; import java.io.File; import java.io.IOException; import java.net.SocketTimeoutException; import java.net.URISyntaxException; import java.net.URL; import java.util.Hashtable; import java.util.concurrent.TimeUnit; import net.dev123.commons.Constants; import net.dev123.commons.ImageInfo; import net.dev123.commons.ImageInfo.Format; import net.dev123.commons.ServiceProvider; import net.dev123.commons.http.config.HttpConfiguration; import net.dev123.commons.http.config.HttpConfigurationFactory; import net.dev123.commons.oauth.OAuthException; import net.dev123.commons.util.MimeTypeUtil; import net.dev123.commons.util.StringUtil; import net.dev123.exception.ExceptionCode; import net.dev123.exception.LibException; import net.dev123.exception.LibRuntimeException; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.HttpVersion; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.CookieStore; import org.apache.http.client.HttpClient; import org.apache.http.client.HttpRequestRetryHandler; import org.apache.http.client.HttpResponseException; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.params.ClientPNames; import org.apache.http.client.protocol.ClientContext; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.params.ConnManagerParams; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * HttpRequestHelper * * @version * @author 马庆升 * @time 2010-8-6 下午04:01:35 */ public class HttpRequestHelper { private static final Logger logger = LoggerFactory.getLogger(HttpRequestHelper.class.getSimpleName()); private static ClientConnectionManager connectionManager; private static HttpHost globalProxy; private static UsernamePasswordCredentials globalProxyCredentials; //代理的用户认证信息 private static MimeTypeUtil mimeTypeUtil = MimeTypeUtil.getSingleton(); private static Hashtable<ServiceProvider, HttpClient> spHttpClients; static { spHttpClients = new Hashtable<ServiceProvider, HttpClient>(); } private static HttpClient getHttpClient(ServiceProvider sp) { HttpConfiguration conf = HttpConfigurationFactory.getHttpConfiguration(sp); HttpClient httpClient = spHttpClients.get(sp); if (httpClient == null) { httpClient = createHttpClient(conf); spHttpClients.put(sp, httpClient); if (Constants.DEBUG) { logger.debug("Init HttpClient for {}", sp); } } return httpClient; } private static synchronized HttpClient createHttpClient(HttpConfiguration config) { if (config == null) { return null; } if (connectionManager == null) { connectionManager = createConnectionManager(); } HttpParams httpParams = new BasicHttpParams(); if (config.getHttpConnectionTimeout() > 0) { httpParams.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, config.getHttpConnectionTimeout()); } if (config.getHttpReadTimeout() > 0) { httpParams.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, config.getHttpReadTimeout()); } // 设置http.protocol.expect-continue参数为false,即不使用Expect:100-Continue握手, // 因为如果服务器不支持HTTP 1.1,则会导致HTTP 417错误。 HttpProtocolParams.setUseExpectContinue(httpParams, false); // 设置User-Agent为YiBo HttpProtocolParams.setUserAgent(httpParams, config.getUserAgent()); // 设置HTTP版本为 HTTP 1.1 HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1); DefaultHttpClient httpClient = new YiBoHttpClient(connectionManager, httpParams); // DefaultHttpClient httpClient = new DefaultHttpClient(connectionManager, httpParams); updateProxySetting(config, httpClient); if (config.isUseGzip()) { httpClient.addRequestInterceptor(new GzipRequestInterceptor()); httpClient.addResponseInterceptor(new GzipResponseInterceptor()); } if (config.getHttpRetryCount() > 0) { HttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(config.getHttpRetryCount(), true); httpClient.setHttpRequestRetryHandler(retryHandler); } return httpClient; } private static void updateProxySetting(HttpConfiguration config, DefaultHttpClient httpClient) { if (config == null || httpClient == null){ return; } HttpHost[] proxyChain = null; if (globalProxy != null) { //全局代理设置 proxyChain = new HttpHost[] {globalProxy}; if (globalProxyCredentials != null){ AuthScope globalProxyAuthScope = new AuthScope(globalProxy.getHostName(), globalProxy.getPort()); httpClient.getCredentialsProvider().setCredentials(globalProxyAuthScope, globalProxyCredentials); } } if (config.isUseProxy() && StringUtil.isNotEmpty(config.getHttpProxyHost())){ HttpHost spProxy = new HttpHost(config.getHttpProxyHost(), config.getHttpProxyPort()); if (globalProxy != null){ proxyChain = new HttpHost[] {globalProxy, spProxy}; } else { proxyChain = new HttpHost[] {spProxy}; } if (StringUtil.isNotEmpty(config.getHttpProxyUser())){ AuthScope spProxyAuthScope = new AuthScope(spProxy.getHostName(), spProxy.getPort()); UsernamePasswordCredentials spProxyCredentials = new UsernamePasswordCredentials( config.getHttpProxyUser(), config.getHttpProxyPassword()); httpClient.getCredentialsProvider().setCredentials(spProxyAuthScope, spProxyCredentials); } } httpClient.setRoutePlanner(new YiBoHttpRoutePlanner(connectionManager.getSchemeRegistry(), proxyChain)); } private static synchronized ClientConnectionManager createConnectionManager() { if (connectionManager != null) { return connectionManager; } // Create and initialize scheme registry SchemeRegistry schemeRegistry = new SchemeRegistry(); Scheme httpScheme = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80); //Scheme httpsScheme = new Scheme("https", SSLSocketFactory.getSocketFactory(), 443); Scheme httpsScheme = new Scheme("https", YiBoSSLSocketFactory.getSocketFactory(), 443); schemeRegistry.register(httpScheme); schemeRegistry.register(httpsScheme); HttpParams managerParams = new BasicHttpParams(); //设置连接池允许的最大连接数 ConnManagerParams.setMaxTotalConnections(managerParams, Constants.CONNECTION_POOL_SIZE); //设置连接池连接超时时间 ConnManagerParams.setTimeout(managerParams, Constants.CONNECTION_TIME_OUT); connectionManager = new ThreadSafeClientConnManager(managerParams, schemeRegistry); return connectionManager; } public static <T> T execute(HttpRequestMessage httpRequestMessage, ResponseHandler<T> responseHandler) throws LibException { T result = null; try { HttpRequest httpRequest = HttpRequestBuilder.newHttpRequest(httpRequestMessage); if (Constants.DEBUG) { logger.debug("HttpRequestMessage {}:{}", httpRequest.getRequestLine().getMethod(), httpRequest.getRequestLine().getUri()); } ServiceProvider serviceProvider = ServiceProvider.None; if (httpRequestMessage.getAuth() != null) { serviceProvider = httpRequestMessage.getAuth().getServiceProvider(); } // Create a local instance of cookie store CookieStore cookieStore = new BasicCookieStore(); // Create local HTTP context HttpContext localContext = new BasicHttpContext(); // Bind custom cookie store to the local context localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); HttpClient httpClient = getHttpClient(serviceProvider); result = httpClient.execute((HttpUriRequest) httpRequest, responseHandler, localContext); } catch (SocketTimeoutException e) { throw new LibException(ExceptionCode.NET_SOCKET_TIME_OUT, e); } catch (HttpResponseException e) { throw new LibException(e.getStatusCode(), e); } catch (ClientProtocolException e) { throw new LibException(ExceptionCode.CLIENT_PROTOCOL_EXCEPTION, e); } catch (IOException e) { throw new LibException(ExceptionCode.NET_I_O_EXCEPTION, e); } catch (OAuthException e) { throw new LibException(ExceptionCode.OAUTH_EXCEPTION, e); } catch (URISyntaxException e) { throw new LibException(ExceptionCode.URI_SYNTAX_ERROR, e); } catch (LibRuntimeException e) { throw new LibException(e.getStatusCode(), e.getErrorDescription()); } return result; } public static ImageInfo getImageInfo(String url) throws LibException { if (StringUtil.isEmpty(url)) { return null; } if (Constants.DEBUG) { logger.debug("Get ImageInfo : {} " , url); } ImageInfo info = null; try { HttpGet urlGet = new HttpGet(url); HttpClient httpClient = getHttpClient(ServiceProvider.None); HttpResponse response = httpClient.execute(urlGet); String extensionName = mimeTypeUtil.getExtensionFromMimeType( response.getEntity().getContentType().getValue()); Format format = Format.valueOf(extensionName.toUpperCase()); info = new ImageInfo(new URL(url)); info.setFormat(format); // 设置图片格式 info.setSize(response.getEntity().getContentLength()); // 获取文件大小 info.setHeight(-1); // 设置高度为-1,不探测 info.setWidth(-1); // 设置宽度为-1,不探测 urlGet.abort(); // 放弃执行此请求 } catch (SocketTimeoutException e) { throw new LibException(ExceptionCode.NET_SOCKET_TIME_OUT, e); } catch (ClientProtocolException e) { throw new LibException(ExceptionCode.CLIENT_PROTOCOL_EXCEPTION, e); } catch (IOException e) { throw new LibException(ExceptionCode.NET_I_O_EXCEPTION, e); } catch (LibRuntimeException e) { throw new LibException(e.getStatusCode(), e.getErrorDescription()); } catch (NullPointerException e) { // 什么都不做,部分图片获取时重定向过程中出现空指针异常 } return info; } public static byte[] getContentBytes(String url) throws LibException { if (Constants.DEBUG) { logger.debug("Download url content : {} " , url); } byte[] byteArray = null; if (StringUtil.isEmpty(url)) { return byteArray; } try { HttpGet urlGet = new HttpGet(url); HttpClient httpClient = getHttpClient(ServiceProvider.None); byteArray = httpClient.execute(urlGet, new ByteArrayResponseHandler()); } catch (SocketTimeoutException e) { throw new LibException(ExceptionCode.NET_SOCKET_TIME_OUT, e); } catch (ClientProtocolException e) { throw new LibException(ExceptionCode.CLIENT_PROTOCOL_EXCEPTION, e); } catch (IOException e) { throw new LibException(ExceptionCode.NET_I_O_EXCEPTION, e); } catch (LibRuntimeException e) { throw new LibException(e.getStatusCode(), e.getErrorDescription()); } catch (NullPointerException e) { //什么都不做,部分图片获取时重定向过程中出现空指针异常 } return byteArray; } /* * 直接写 */ public static File getBitmapFile(String url, File destFile) throws LibException { if (Constants.DEBUG) { logger.debug("Download Image : {} " , url); } File bitmapFile = null; if (StringUtil.isEmpty(url)) { return null; } try { HttpGet urlGet = new HttpGet(url); HttpClient httpClient = getHttpClient(ServiceProvider.None); bitmapFile = httpClient.execute(urlGet, new FileResponseHandler(destFile)); } catch (SocketTimeoutException e) { throw new LibException(ExceptionCode.NET_SOCKET_TIME_OUT, e); } catch (ClientProtocolException e) { throw new LibException(ExceptionCode.CLIENT_PROTOCOL_EXCEPTION, e); } catch (IOException e) { throw new LibException(ExceptionCode.NET_I_O_EXCEPTION, e); } catch (LibRuntimeException e) { throw new LibException(e.getStatusCode(), e.getErrorDescription()); } catch (NullPointerException e) { //什么都不做,部分图片获取时重定向过程中出现空指针异常 } return bitmapFile; } public static String getRedirectUrl(String url) throws LibException { if (StringUtil.isEmpty(url)) { return null; } String redirect = null; try { HttpGet urlGet = new HttpGet(url); // Set HANDLE_REDIRECTS to false urlGet.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false); // Create a local instance of cookie store CookieStore cookieStore = new BasicCookieStore(); // Create local HTTP context HttpContext localContext = new BasicHttpContext(); // Bind custom cookie store to the local context localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); HttpResponse response = getHttpClient(ServiceProvider.None).execute(urlGet, localContext); if (response.containsHeader("location")) { redirect = response.getFirstHeader("location").getValue(); } urlGet.abort(); } catch (SocketTimeoutException e) { throw new LibException(ExceptionCode.NET_SOCKET_TIME_OUT, e); } catch (ClientProtocolException e) { throw new LibException(ExceptionCode.CLIENT_PROTOCOL_EXCEPTION, e); } catch (IOException e) { throw new LibException(ExceptionCode.NET_I_O_EXCEPTION, e); } catch (LibRuntimeException e) { throw new LibException(e.getStatusCode(), e.getErrorDescription()); } catch (NullPointerException e) { //什么都不做,部分图片获取时重定向过程中出现空指针异常 } return redirect; } public static synchronized void setGlobalProxy(String hostname, int port, String username, String password) { globalProxy = null; globalProxyCredentials = null; if (StringUtil.isNotEmpty(hostname) && port > 0) { globalProxy = new HttpHost(hostname, port); if (StringUtil.isNotEmpty(username)) { globalProxyCredentials = new UsernamePasswordCredentials(username, password); } } for (ServiceProvider sp : spHttpClients.keySet()) { HttpConfiguration config = HttpConfigurationFactory.getHttpConfiguration(sp); DefaultHttpClient httpClient = (DefaultHttpClient) spHttpClients.get(sp); updateProxySetting(config, httpClient); } } /** * 关闭连接池,清理helper资源 */ public static synchronized void shutdown() { if (connectionManager != null) { connectionManager.shutdown(); connectionManager = null; } spHttpClients.clear(); globalProxy = null; globalProxyCredentials = null; } public static void evictConnections() { if (connectionManager == null) { return; } synchronized (HttpRequestHelper.class) { if (Constants.DEBUG) { logger.debug("Connections Eviction"); } // Close expired connections connectionManager.closeExpiredConnections(); // Optionally, close connections // that have been idle longer than 30 second connectionManager.closeIdleConnections(30, TimeUnit.SECONDS); } } }