package com.mzeat.http; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; import java.nio.charset.Charset; import java.util.ArrayList; import javax.net.ssl.SSLHandshakeException; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.HttpVersion; import org.apache.http.NoHttpResponseException; import org.apache.http.ProtocolException; 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.CredentialsProvider; import org.apache.http.client.HttpRequestRetryHandler; import org.apache.http.client.RedirectHandler; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.params.HttpClientParams; 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.params.ConnRoutePNames; 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.conn.ssl.SSLSocketFactory; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.ExecutionContext; import org.apache.http.protocol.HTTP; import org.apache.http.protocol.HttpContext; import org.json.JSONException; import org.json.JSONObject; import android.util.Log; /** * Wrap of org.apache.http.impl.client.DefaultHttpClient * 封装DefaultHttpClient类,有post和get方法 * @author lds * */ public class HttpClient { private static final String TAG = "HttpClient"; private static final boolean DEBUG = true; /** OK: Success! */ public static final int OK = 200; /** Not Modified: There was no new data to return. */ public static final int NOT_MODIFIED = 304; /** * Bad Request: The request was invalid. An accompanying error message will * explain why. This is the status code will be returned during rate * limiting. */ public static final int BAD_REQUEST = 400; /** Not Authorized: Authentication credentials were missing or incorrect. */ public static final int NOT_AUTHORIZED = 401; /** * Forbidden: The request is understood, but it has been refused. An * accompanying error message will explain why. */ public static final int FORBIDDEN = 403; /** * Not Found: The URI requested is invalid or the resource requested, such * as a user, does not exists. */ public static final int NOT_FOUND = 404; /** * Not Acceptable: Returned by the Search API when an invalid format is * specified in the request. */ public static final int NOT_ACCEPTABLE = 406; /** * Internal Server Error: Something is broken. Please post to the group so * the Weibo team can investigate. */ public static final int INTERNAL_SERVER_ERROR = 500; /** Bad Gateway: Weibo is down or being upgraded. */ public static final int BAD_GATEWAY = 502; /** * Service Unavailable: The Weibo servers are up, but overloaded with * requests. Try again later. The search and trend methods use this to * indicate when you are being rate limited. */ public static final int SERVICE_UNAVAILABLE = 503; private static final int CONNECTION_TIMEOUT_MS = 8 * 1000; private static final int SOCKET_TIMEOUT_MS = 8 * 1000; public static final int RETRIEVE_LIMIT = 20; public static final int RETRIED_TIME = 3; private static final String SERVER_HOST = "api.fanfou.com"; private DefaultHttpClient mClient; private AuthScope mAuthScope; private BasicHttpContext localcontext; private String mUserId; private String mPassword; /** * 需要加载http头中,每次请求都必须带上。 格式为:Mozilla/5.5 (设备名称;操作系统;设备串号;分辨率;用户语言) 产品名称/发布日期 * ver/版本号 */ private String Mozilla = null; private static boolean isAuthenticationEnabled = false; /** * 构造方法 */ public HttpClient() { prepareHttpClient(); } /** * 构造方法 * * @param user_id * auth user * @param password * auth password */ public HttpClient(String user_id, String password) { prepareHttpClient(); setCredentials(user_id, password); } /** * 重新设置 Empty the credentials * */ public void reset() { setCredentials("", ""); } /** * 取得用户ID * * @return authed user id */ public String getUserId() { return mUserId; } /** * 取得密码 * * @return authed user password */ public String getPassword() { return mPassword; } /** * 设置代理 * * @param hostname * the hostname (IP or DNS name) * @param port * the port number. -1 indicates the scheme default port. * @param scheme * the name of the scheme. null indicates the default scheme */ public void setProxy(String host, int port, String scheme) { HttpHost proxy = new HttpHost(host, port, scheme); mClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); } /** * 取消代理 */ public void removeProxy() { mClient.getParams().removeParameter(ConnRoutePNames.DEFAULT_PROXY); } /** * 启用调试 */ private void enableDebug() { Log.i(TAG, "enable apache.http debug"); java.util.logging.Logger.getLogger("org.apache.http").setLevel( java.util.logging.Level.FINEST); java.util.logging.Logger.getLogger("org.apache.http.wire").setLevel( java.util.logging.Level.FINER); java.util.logging.Logger.getLogger("org.apache.http.headers").setLevel( java.util.logging.Level.OFF); } /** * 准备HttpClient Setup DefaultHttpClient * * Use ThreadSafeClientConnManager. * */ private void prepareHttpClient() { if (DEBUG) { enableDebug(); } // Create and initialize HTTP parameters 建立和初始化HTTP参数 HttpParams params = new BasicHttpParams(); ConnManagerParams.setMaxTotalConnections(params, 10); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); // Create and initialize scheme registry 建立和初始化scheme registry SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory .getSocketFactory(), 80)); schemeRegistry.register(new Scheme("https", SSLSocketFactory .getSocketFactory(), 443)); // Create an HttpClient with the ThreadSafeClientConnManager. // 建立一个ThreadSafeClientConnManager的HttpClient ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry); mClient = new DefaultHttpClient(cm, params); // TODO: need to release this connection in httpRequest() // cm.releaseConnection(conn, validDuration, timeUnit); // Setup BasicAuth 设置BasicAuth BasicScheme basicScheme = new BasicScheme(); mAuthScope = new AuthScope(SERVER_HOST, AuthScope.ANY_PORT); // mClient.setAuthSchemes(authRegistry); mClient.setCredentialsProvider(new BasicCredentialsProvider()); // Generate BASIC scheme object and stick it to the local // execution context localcontext = new BasicHttpContext(); localcontext.setAttribute("preemptive-auth", basicScheme); // first request interceptor mClient.addRequestInterceptor(preemptiveAuth, 0); } /** * HttpRequestInterceptor for DefaultHttpClient 默认HTTP客户端的请求拦截器 */ private HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() { @Override public void process(final HttpRequest request, final HttpContext context) { AuthState authState = (AuthState) context .getAttribute(ClientContext.TARGET_AUTH_STATE); CredentialsProvider credsProvider = (CredentialsProvider) context .getAttribute(ClientContext.CREDS_PROVIDER); HttpHost targetHost = (HttpHost) context .getAttribute(ExecutionContext.HTTP_TARGET_HOST); if (authState.getAuthScheme() == null) { AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort()); Credentials creds = credsProvider.getCredentials(authScope); if (creds != null) { authState.setAuthScheme(new BasicScheme()); authState.setCredentials(creds); } } } }; /** * Setup Credentials for HTTP Basic Auth 给HTTP基本认证设置证书 * * @param username * @param password */ public void setCredentials(String username, String password) { mUserId = username; mPassword = password; mClient.getCredentialsProvider().setCredentials(mAuthScope, new UsernamePasswordCredentials(username, password)); isAuthenticationEnabled = true; } /** * post方法1,有参数,没有文件,带验证。 * * @param url * @param postParams * @param authenticated * @return * @throws HttpException */ public Response post(String url, ArrayList<BasicNameValuePair> postParams, boolean authenticated) throws HttpException { if (null == postParams) { postParams = new ArrayList<BasicNameValuePair>(); } return httpRequest(url, postParams, authenticated, HttpPost.METHOD_NAME); } public Response post(String url, ArrayList<BasicNameValuePair> postParams, ArrayList<File> file, ArrayList<String> filename ) throws HttpException { return httpRequest(url, postParams, file, filename, false, HttpPost.METHOD_NAME); } /** * POST方法之2,有参数,没有文件,不带验证。 * * @param url * @param params * @return * @throws HttpException */ public Response post(String url, ArrayList<BasicNameValuePair> params) throws HttpException { return httpRequest(url, params, false, HttpPost.METHOD_NAME); } /** * POST方法之3,无参数,没有文件,带验证。 * * @param url * @param authenticated * @return * @throws HttpException */ public Response post(String url, boolean authenticated) throws HttpException { return httpRequest(url, null, authenticated, HttpPost.METHOD_NAME); } /** * post方法之4,无参数,没有文件,不带验证。 * * @param url * @return * @throws HttpException */ public Response post(String url) throws HttpException { return httpRequest(url, null, false, HttpPost.METHOD_NAME); } /** * POST方法之5,有参数,带一个文件和文件名。 * * @param url * @param params * @param file * @return * @throws HttpException */ public Response post(String url, ArrayList<BasicNameValuePair> params, File file,String filename) throws HttpException { return httpRequest(url, params, file, filename,false, HttpPost.METHOD_NAME); } /** * POST方法之6,无参数,带一个文件和文件名。 * * @param url * @param file * @return * @throws HttpException */ public Response post(String url, File file, String filename) throws HttpException { return httpRequest(url, null, file,filename ,false, HttpPost.METHOD_NAME); } /** * POST方法之7,无参数,带一个文件和文件名,带验证。 * * @param url * @param file * @param authenticate * @return * @throws HttpException */ public Response post(String url, File file, String filename,boolean authenticate) throws HttpException { return httpRequest(url, null, file,filename, authenticate, HttpPost.METHOD_NAME); } /** * GET方法之一 * * @param url * @param params * @param authenticated * @return * @throws HttpException */ public Response get(String url, ArrayList<BasicNameValuePair> params, boolean authenticated) throws HttpException { return httpRequest(url, params, authenticated, HttpGet.METHOD_NAME); } /** * GET方法之一 * * @param url * @param params * @return * @throws HttpException */ public Response get(String url, ArrayList<BasicNameValuePair> params) throws HttpException { return httpRequest(url, params, false, HttpGet.METHOD_NAME); } /** * HttpGet方法之一 * * @param url * @return * @throws HttpException * */ public Response get(String url) throws HttpException { return httpRequest(url, null, false, HttpGet.METHOD_NAME); } /** * GET方法之一 * * @param url * @param authenticated * @return * @throws HttpException */ public Response get(String url, boolean authenticated) throws HttpException { return httpRequest(url, null, authenticated, HttpGet.METHOD_NAME); } /** * HttpRequest方法之一,没有文件 * * @param url * @param postParams * @param authenticated * @param httpMethod * @return * @throws HttpException */ public Response httpRequest(String url, ArrayList<BasicNameValuePair> postParams, boolean authenticated, String httpMethod) throws HttpException { return httpRequest(url, postParams, null,"", authenticated, httpMethod); } /** * Execute the DefaultHttpClient * * @param url * target * @param postParams * @param file * can be NULL * @param authenticated * need or not * @param httpMethod * HttpPost.METHOD_NAME HttpGet.METHOD_NAME * HttpDelete.METHOD_NAME * @return Response from server * @throws HttpException * 此异常包装了一系列底层异常 <br /> * <br /> * 1. 底层异常, 可使用getCause()查看: <br /> * <li>URISyntaxException, 由`new URI` 引发的.</li> <li>IOException, * 由`createMultipartEntity` 或 `UrlEncodedFormEntity` 引发的.</li> * <li>IOException和ClientProtocolException, * 由`HttpClient.execute` 引发的.</li><br /> * * 2. 当响应码不为200时报出的各种子类异常: <li>HttpRequestException, * 通常发生在请求的错误,如请求错误了 网址导致404等, 抛出此异常, 首先检查request log, * 确认不是人为错误导致请求失败</li> <li>HttpAuthException, 通常发生在Auth失败, * 检查用于验证登录的用户名/密码/KEY等</li> <li>HttpRefusedException, * 通常发生在服务器接受到请求, 但拒绝请求, 可是多种原因, 具体原因 服务器会返回拒绝理由, * 调用HttpRefusedException#getError#getMessage查看</li> <li> * HttpServerException, 通常发生在服务器发生错误时, 检查服务器端是否在正常提供服务</li> <li> * HttpException, 其他未知错误.</li> * @throws UnsupportedEncodingException */ public Response httpRequest(String url, ArrayList<BasicNameValuePair> postParams, File file,String filename, boolean authenticated, String httpMethod) throws HttpException { Log.i(TAG, "Sending " + httpMethod + " request to " + url); // 开始时间 long startTime = System.currentTimeMillis(); String keyUrl = url; // 构造请求url if (null != postParams) { StringBuilder sb = new StringBuilder(); for (BasicNameValuePair nameValue : postParams) { sb.append(nameValue.getName()); sb.append("="); sb.append(nameValue.getValue()); } keyUrl = url + "?" + sb.toString(); Log.e(TAG, keyUrl); } URI uri = createURI(url); HttpResponse response = null; Response res = null; HttpUriRequest method = null; // Create POST, GET or DELETE METHOD // 建立POST,GET或DELECT方法 method = createMethod(httpMethod, uri, file,filename, postParams); // Setup ConnectionParams // 建立连接参数 SetupHTTPConnectionParams(method); // Execute Request // 执行请求 try { response = mClient.execute(method, localcontext); res = new Response(response, keyUrl); } catch (ClientProtocolException e) { Log.e(TAG, e.getMessage(), e); throw new HttpException(e.getMessage(), e); } catch (IOException ioe) { throw new HttpException(ioe.getMessage(), ioe); } catch (IllegalStateException e) { Log.e(TAG, e.getMessage(), e); throw new HttpException(e.getMessage(), e); } catch (IllegalArgumentException e) { Log.e(TAG, e.getMessage(), e); throw new HttpException(e.getMessage(), e); } catch (NullPointerException e) { Log.e(TAG, e.getMessage(), e); throw new HttpException(e.getMessage(), e); } if (response != null) { int statusCode = response.getStatusLine().getStatusCode(); // It will throw a weiboException while status code is not 200 HandleResponseStatusCode(statusCode, res); } else { Log.e(TAG, "response is null"); } //结束时间 long endTime = System.currentTimeMillis(); Log.d(TAG, "Http request in " + (endTime - startTime)); // TODO: response内容DEBUG输出 return res; } /** * Execute the DefaultHttpClient * * @param url * target * @param postParams * @param file * can be NULL * @param authenticated * need or not * @param httpMethod * HttpPost.METHOD_NAME HttpGet.METHOD_NAME * HttpDelete.METHOD_NAME * @return Response from server * @throws HttpException * 此异常包装了一系列底层异常 <br /> * <br /> * 1. 底层异常, 可使用getCause()查看: <br /> * <li>URISyntaxException, 由`new URI` 引发的.</li> <li>IOException, * 由`createMultipartEntity` 或 `UrlEncodedFormEntity` 引发的.</li> * <li>IOException和ClientProtocolException, * 由`HttpClient.execute` 引发的.</li><br /> * * 2. 当响应码不为200时报出的各种子类异常: <li>HttpRequestException, * 通常发生在请求的错误,如请求错误了 网址导致404等, 抛出此异常, 首先检查request log, * 确认不是人为错误导致请求失败</li> <li>HttpAuthException, 通常发生在Auth失败, * 检查用于验证登录的用户名/密码/KEY等</li> <li>HttpRefusedException, * 通常发生在服务器接受到请求, 但拒绝请求, 可是多种原因, 具体原因 服务器会返回拒绝理由, * 调用HttpRefusedException#getError#getMessage查看</li> <li> * HttpServerException, 通常发生在服务器发生错误时, 检查服务器端是否在正常提供服务</li> <li> * HttpException, 其他未知错误.</li> * @throws UnsupportedEncodingException */ public Response httpRequest(String url, ArrayList<BasicNameValuePair> postParams, ArrayList<File> file, ArrayList<String> filename, boolean authenticated, String httpMethod) throws HttpException { Log.i(TAG, "Sending " + httpMethod + " request to " + url); // 开始时间 long startTime = System.currentTimeMillis(); String keyUrl = url; // 构造请求url if (null != postParams) { StringBuilder sb = new StringBuilder(); for (BasicNameValuePair nameValue : postParams) { sb.append(nameValue.getName()); sb.append("="); sb.append(nameValue.getValue()); //sb.append("?"); } //keyUrl = url + "?" + sb.toString(); keyUrl = url + sb.toString(); Log.e(TAG, keyUrl); } URI uri = createURI(url); HttpResponse response = null; Response res = null; HttpUriRequest method = null; // Create POST, GET or DELETE METHOD // 建立POST,GET或DELECT方法 method = createMethod(httpMethod, uri, file,filename, postParams); // Setup ConnectionParams // 建立连接参数 SetupHTTPConnectionParams(method); // Execute Request // 执行请求 try { response = mClient.execute(method, localcontext); res = new Response(response, keyUrl); } catch (ClientProtocolException e) { Log.e(TAG, e.getMessage(), e); throw new HttpException(e.getMessage(), e); } catch (IOException ioe) { throw new HttpException(ioe.getMessage(), ioe); } catch (IllegalStateException e) { Log.e(TAG, e.getMessage(), e); throw new HttpException(e.getMessage(), e); } catch (IllegalArgumentException e) { Log.e(TAG, e.getMessage(), e); throw new HttpException(e.getMessage(), e); } catch (NullPointerException e) { Log.e(TAG, e.getMessage(), e); throw new HttpException(e.getMessage(), e); } if (response != null) { int statusCode = response.getStatusLine().getStatusCode(); // It will throw a weiboException while status code is not 200 HandleResponseStatusCode(statusCode, res); } else { Log.e(TAG, "response is null"); } //结束时间 long endTime = System.currentTimeMillis(); Log.d(TAG, "Http request in " + (endTime - startTime)); // TODO: response内容DEBUG输出 return res; } /** * CreateURI from URL string * 从URL字符串建立URI * @param url * @return request URI * @throws HttpException * Cause by URISyntaxException */ private URI createURI(String url) throws HttpException { URI uri; try { uri = new URI(url); Log.e(TAG, url); } catch (URISyntaxException e) { Log.e(TAG, e.getMessage(), e); throw new HttpException("Invalid URL."); } return uri; } /** * 创建可带一个File的MultipartEntity * * @param filename * 文件名 * @param file * 文件 * @param postParams * 其他POST参数 * @return 带文件和其他参数的Entity * @throws UnsupportedEncodingException */ private MultipartEntity createMultipartEntity(String filename, File file, ArrayList<BasicNameValuePair> postParams) throws UnsupportedEncodingException { MultipartEntity entity = new MultipartEntity(); // Don't try this. Server does not appear to support chunking. // entity.addPart("media", new InputStreamBody(imageStream, "media")); entity.addPart(filename, new FileBody(file)); Charset chars = Charset.forName("UTF-8"); for (BasicNameValuePair param : postParams) { entity.addPart(param.getName(), new StringBody(param.getValue(),chars)); } return entity; } /** * 创建可带几个File的MultipartEntity * * @param filename * 文件名 * @param file * 文件 * @param postParams * 其他POST参数 * @return 带文件和其他参数的Entity * @throws UnsupportedEncodingException * @throws HttpException */ private MultipartEntity createMultipartEntity(ArrayList<String> filename, ArrayList<File> file, ArrayList<BasicNameValuePair> postParams) throws UnsupportedEncodingException, HttpException { MultipartEntity entity = new MultipartEntity(); // Don't try this. Server does not appear to support chunking. // entity.addPart("media", new InputStreamBody(imageStream, "media")); for (int i = 0; i < file.size(); i++) { entity.addPart(filename.get(i), new FileBody(file.get(i))); } Charset chars = Charset.forName("UTF-8"); for (BasicNameValuePair param : postParams) { entity.addPart(param.getName(), new StringBody(param.getValue(),chars)); } return entity; } /** * Create request method, such as POST, GET, DELETE 建立请求方法,如POST/GET/DELETE * * @param httpMethod * "GET","POST","DELETE" * @param uri * 请求的URI * @param file * 可为null * @param postParams * POST参数 * @return httpMethod Request implementations for the various HTTP methods * like GET and POST. * @throws HttpException * createMultipartEntity 或 UrlEncodedFormEntity引发的IOException */ private HttpUriRequest createMethod(String httpMethod, URI uri, File file,String filename, ArrayList<BasicNameValuePair> postParams) throws HttpException { HttpUriRequest method; if (httpMethod.equalsIgnoreCase(HttpPost.METHOD_NAME)) { // POST METHOD HttpPost post = new HttpPost(uri); // See this: // http://groups.google.com/group/twitter-development-talk/browse_thread/thread/e178b1d3d63d8e3b post.getParams().setBooleanParameter( "http.protocol.expect-continue", false); try { HttpEntity entity = null; // 当文件不为空时 if (null != file) { entity = createMultipartEntity(filename, file, postParams); post.setEntity(entity); } else if (null != postParams)// 当参数不为空时 { entity = new UrlEncodedFormEntity(postParams, HTTP.UTF_8); post.setEntity(entity); } } catch (IOException ioe) { throw new HttpException(ioe.getMessage(), ioe); } method = post; } else if (httpMethod.equalsIgnoreCase(HttpDelete.METHOD_NAME)) { method = new HttpDelete(uri); } else { method = new HttpGet(uri); } return method; } /** * Setup HTTPConncetionParams * 设置HTTP连接参数 * @param method */ private void SetupHTTPConnectionParams(HttpUriRequest method) { HttpConnectionParams.setConnectionTimeout(method.getParams(),CONNECTION_TIMEOUT_MS); HttpConnectionParams.setSoTimeout(method.getParams(), SOCKET_TIMEOUT_MS); HttpClientParams.setRedirecting(method.getParams(), true); mClient.setHttpRequestRetryHandler(requestRetryHandler); method.addHeader("Accept-Encoding", "gzip, deflate"); method.addHeader("User-Agent", Mozilla); //手动设置重定向 mClient.setRedirectHandler(new RedirectHandler() { @Override public boolean isRedirectRequested(HttpResponse response, HttpContext context) { int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY || statusCode == HttpStatus.SC_SEE_OTHER || statusCode == HttpStatus.SC_TEMPORARY_REDIRECT) return true; else return false; } @Override public URI getLocationURI(HttpResponse response, HttpContext context) throws ProtocolException { int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY || statusCode == HttpStatus.SC_SEE_OTHER || statusCode == HttpStatus.SC_TEMPORARY_REDIRECT) { Header[] headers = response.getHeaders("Location"); if (headers != null && headers.length != 0) { String newUrl = headers[headers.length - 1].getValue(); try { if (newUrl.indexOf("c/..\\") != -1) { String url = newUrl.replace("c/..\\", ""); url = url.replace("\\", "/"); newUrl = url; Log.e(TAG, url); } return new URI(newUrl); } catch (URISyntaxException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } return null; } }); } /** * Create request method, such as POST, GET, DELETE 建立请求方法,如POST/GET/DELETE * * @param httpMethod * "GET","POST","DELETE" * @param uri * 请求的URI * @param file * 可为null * @param postParams * POST参数 * @return httpMethod Request implementations for the various HTTP methods * like GET and POST. * @throws HttpException * createMultipartEntity 或 UrlEncodedFormEntity引发的IOException */ private HttpUriRequest createMethod(String httpMethod, URI uri, ArrayList<File> file,ArrayList<String> filename, ArrayList<BasicNameValuePair> postParams) throws HttpException { HttpUriRequest method; if (httpMethod.equalsIgnoreCase(HttpPost.METHOD_NAME)) { // POST METHOD HttpPost post = new HttpPost(uri); // See this: // http://groups.google.com/group/twitter-development-talk/browse_thread/thread/e178b1d3d63d8e3b post.getParams().setBooleanParameter( "http.protocol.expect-continue", false); try { HttpEntity entity = null; // 当文件不为空时 if (null != file) { entity = createMultipartEntity(filename, file, postParams); post.setEntity(entity); } else if (null != postParams)// 当参数不为空时 { entity = new UrlEncodedFormEntity(postParams, HTTP.UTF_8); post.setEntity(entity); } } catch (IOException ioe) { throw new HttpException(ioe.getMessage(), ioe); } method = post; } else if (httpMethod.equalsIgnoreCase(HttpDelete.METHOD_NAME)) { method = new HttpDelete(uri); } else { method = new HttpGet(uri); } return method; } /** * 解析HTTP错误码 * * @param statusCode * @return */ private static String getCause(int statusCode) { String cause = null; switch (statusCode) { case NOT_MODIFIED: break; case BAD_REQUEST: cause = "The request was invalid. An accompanying error message will explain why. This is the status code will be returned during rate limiting."; break; case NOT_AUTHORIZED: cause = "Authentication credentials were missing or incorrect."; break; case FORBIDDEN: cause = "The request is understood, but it has been refused. An accompanying error message will explain why."; break; case NOT_FOUND: cause = "The URI requested is invalid or the resource requested, such as a user, does not exists."; break; case NOT_ACCEPTABLE: cause = "Returned by the Search API when an invalid format is specified in the request."; break; case INTERNAL_SERVER_ERROR: cause = "Something is broken. Please post to the group so the Weibo team can investigate."; break; case BAD_GATEWAY: cause = "Weibo is down or being upgraded."; break; case SERVICE_UNAVAILABLE: cause = "Service Unavailable: The Weibo servers are up, but overloaded with requests. Try again later. The search and trend methods use this to indicate when you are being rate limited."; break; default: cause = ""; } return statusCode + ":" + cause; } /** * 判断是否启用认证 * * @return */ public boolean isAuthenticationEnabled() { return isAuthenticationEnabled; } /** * 是否启用日志 * * @param msg */ public static void log(String msg) { if (DEBUG) { Log.d(TAG, msg); } } /** * Handle Status code 处理状态码 * * @param statusCode * 响应的状态码 * @param res * 服务器响应 * @throws HttpException * 当响应码不为200时都会报出此异常:<br /> * <li>HttpRequestException, 通常发生在请求的错误,如请求错误了 网址导致404等, 抛出此异常, * 首先检查request log, 确认不是人为错误导致请求失败</li> <li>HttpAuthException, * 通常发生在Auth失败, 检查用于验证登录的用户名/密码/KEY等</li> <li> * HttpRefusedException, 通常发生在服务器接受到请求, 但拒绝请求, 可是多种原因, 具体原因 * 服务器会返回拒绝理由, 调用HttpRefusedException#getError#getMessage查看</li> * <li>HttpServerException, 通常发生在服务器发生错误时, 检查服务器端是否在正常提供服务</li> * <li>HttpException, 其他未知错误.</li> */ private void HandleResponseStatusCode(int statusCode, Response res) throws HttpException { String msg = getCause(statusCode) + "\n"; switch (statusCode) { // It's OK, do nothing case OK: break; // Mine mistake, Check the Log case NOT_MODIFIED: case BAD_REQUEST: case NOT_FOUND: case NOT_ACCEPTABLE: { JSONObject json = res.asJSONObject(); try { throw new HttpException(msg + json.getString("msg"), statusCode); } catch (JSONException e) { throw new HttpException(msg + "unknow error!", statusCode); } } // UserName/Password incorrect case NOT_AUTHORIZED: throw new HttpAuthException(msg + res.asString(), statusCode); // Server will return a error message, use // HttpRefusedException#getError() to see. case FORBIDDEN: throw new HttpRefusedException(msg, statusCode); // Something wrong with server case INTERNAL_SERVER_ERROR: case BAD_GATEWAY: case SERVICE_UNAVAILABLE: throw new HttpServerException(msg, statusCode); // Others default: throw new HttpException(msg + res.asString(), statusCode); } } /** * 编码字符串 * * @param value * @return * @throws HttpException */ public static String encode(String value) throws HttpException { try { return URLEncoder.encode(value, HTTP.UTF_8); } catch (UnsupportedEncodingException e_e) { throw new HttpException(e_e.getMessage(), e_e); } } /** * 编码参数 * * @param params * @return * @throws HttpException */ public static String encodeParameters(ArrayList<BasicNameValuePair> params) throws HttpException { StringBuffer buf = new StringBuffer(); for (int j = 0; j < params.size(); j++) { if (j != 0) { buf.append("&"); } try { buf.append(URLEncoder.encode(params.get(j).getName(), "UTF-8")) .append("=") .append(URLEncoder.encode(params.get(j).getValue(), "UTF-8")); Log.e("url", buf.toString()); } catch (java.io.UnsupportedEncodingException neverHappen) { throw new HttpException(neverHappen.getMessage(), neverHappen); } } return buf.toString(); } /** * 异常自动恢复处理, 使用HttpRequestRetryHandler接口实现请求的异常恢复 */ private static HttpRequestRetryHandler requestRetryHandler = new HttpRequestRetryHandler() { // 自定义的恢复策略 public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { // 设置恢复策略,在发生异常时候将自动重试N次 if (executionCount >= RETRIED_TIME) { // Do not retry if over max retry count return false; } if (exception instanceof NoHttpResponseException) { // Retry if the server dropped connection on us return true; } if (exception instanceof SSLHandshakeException) { // Do not retry on SSL handshake exception return false; } HttpRequest request = (HttpRequest) context .getAttribute(ExecutionContext.HTTP_REQUEST); boolean idempotent = (request instanceof HttpEntityEnclosingRequest); if (!idempotent) { // Retry if the request is considered idempotent return true; } return false; } }; }