热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AndroidHttpClient及连接管理器

超文本传输协议HTTP也许是当今互联网上使用的最重要的协议了。尽管java.net包提供了基本通过HTTP访问资源的功能,但它没有提供全面的灵活性和其它很多应用程序需要的功能。HttpClient就
超文本传输协议HTTP也许是当今互联网上使用的最重要的协议了。 尽管java.net包提供了基本通过HTTP访问资源的功能,但它没有提供全面的灵活性和其它很多应用程序需要的功能。

HttpClient就是寻求弥补这项空白的组件,通过提供一个有效的保持更新的功能丰富的软件包来实现客户端最新的HTTP标准和建议。 为扩展而设计同时为基本的HTTP协议提供强大的支持HttpClient组件也许就是构建HTTP客户端应用程序。

HttpClient它是一个客户端的HTTP通信实现库。HttpClient的目标是发送和接收HTTP报文。HttpClient不会去缓存内容,执行嵌 入在HTML页面中的Javascript代码猜测内容类型重新格式化请求/重定向URI或者其它和HTTP运输无关的功能。 


1.执行请求

HttpClient 最重要的功能是执行HTTP方法。一个HTTP方法的执行包含一个或多个HTTP请求/HTTP响应交换,通常由HttpClient的内部来处理。而期 望用户提供一个要执行的请求对象,而HttpClient期望传输请求到目标服务器并返回对应的响应对象或者当执行不成功时抛出异常。 


2.中止请求 
在 一些情况下,由于目标服务器的高负载或客户端有很多活动的请求,那么HTTP请求执行会在预期的时间框内而失败。这时就可能不得不过早地中止请求,解除 封锁在I/O执行中的线程封锁。被HttpClient执行的HTTP请求可以在执行的任意阶段通过调用HttpUriRequest#abort()方 法而中止。这个方法是线程安全的,而且可以从任意线程中调用。当一个HTTP请求被中止时,它的执行线程就封锁在I/O操作中了而且保证通过抛出 InterruptedIOException异常来解锁。


3. 连接管理器关闭 

当一个HttpClient实例不再需要时而且即将走出使用范围,那么关闭连接管理器来保证由管理器保持活动的所有连接被关闭由连接分配的系统资源被释放是很重要的。 

DefaultHttpClient httpclient = new DefaultHttpClient(); 
HttpGet httpget = new HttpGet("http://www.google.com/");
HttpResponse respOnse= httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
System.out.println(response.getStatusLine());
if (entity != null) {
entity.consumeContent();
}
httpclient.getConnectionManager().shutdown();


4. 多线程执行请求 
当配备连接池管理器时比如ThreadSafeClientConnManager,HttpClient可以同时被用来执行多个请求使用多线程执行。 ThreadSafeClientConnManager 将会分配基于它的配置的连接。如果对于给定路由的所有连接都被租出了,那么连接的请求将会阻塞直到一个连接被释放回连接池。它可以通过设置 'http.conn-manager.timeout'为一个正数来保证连接管理器不会在连接请求执行时无限期的被阻塞。如果连接请求不能在给定的时间 周期内被响应,将会抛出ConnectionPoolTimeoutException异常。


5.使用单例HttpClient

在Android开发中我们经常会用到网络连接功能与服务器进行数据的交互,为此Android的SDK提供了Apache的HttpClient来方便我们使用各种Http服务。你可以把HttpClient想象成一个浏览器,通过它的API我们可以很方便的发出GET,POST请求(当然它的功能远不止这些)。


比如你只需以下几行代码就能发出一个简单的GET请求并打印响应结果:

try {
// 创建一个默认的HttpClient
HttpClient httpclient =new DefaultHttpClient();
// 创建一个GET请求
HttpGet request =new HttpGet("www.google.com");
// 发送GET请求,并将响应内容转换成字符串
String respOnse= httpclient.execute(request, new BasicResponseHandler());
Log.v("response text", response);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

为什么要使用单例HttpClient?

对于已经和服务端建立了连接的应用来说,再次调用HttpClient进行网络数据传输时,就不必重新建立新连接了,而可以重用已经建立的连接。这样无疑可以减少开销,提升速度。
    在这个方面,Apache已经做了“连接管理”,默认情况下,就会尽可能的重用已有连接,因此,不需要客户端程序员做任何配置。只是需要注意,Apache的连接管理并不会主动释放建立的连接,需要程序员在不用的时候手动关闭连接。

这只是一段演示代码,实际的项目中的请求与响应处理会复杂一些,并且还要考虑到代码的容错性,但是这并不是本篇的重点。注意代码:

 HttpClient httpclient =new DefaultHttpClient();
在发出HTTP请求前,我们先创建了一个HttpClient对象。那么,在实际项目中,我们很可能在多处需要进行HTTP通信,这时候我们不需要为每个请求都创建一个新的HttpClient。因为之前已经提到,HttpClient就像一个小型的浏览器,对于整个应用,我们只需要一个HttpClient就够了。看到这里,一定有人心里想,这有什么难的,用单例啊!!就像这样:

publicclass CustomerHttpClient {
privatestatic HttpClient customerHttpClient;

private CustomerHttpClient() {
}

publicstatic HttpClient getHttpClient() {
if(null== customerHttpClient) {
customerHttpClient =new DefaultHttpClient();
}
return customerHttpClient;
}
}

那么,哪里不对劲呢?或者说做的还不够完善呢?

多线程!试想,现在我们的应用程序使用同一个HttpClient来管理所有的Http请求,一旦出现并发请求,那么一定会出现多线程的问题。这就好像我们的浏览器只有一个标签页却有多个用户,A要上google,B要上baidu,这时浏览器就会忙不过来了。幸运的是,HttpClient提供了创建线程安全对象的API,帮助我们能很快地得到线程安全的“浏览器”。


解决多线程问题:

使用ThreadSafeClientConnManager管理线程池,如果应用程序采用了多线程进行网络访问,则应该使用Apache封装好的线程安全管理类ThreadSafeClientConnManager来进行管理,这样能够更有效且更安全的管理多线程和连接池中的连接。

    (在网上也看到有人用MultiThreadedHttpConnectionManager进行线程安全管理的,后查了下Apache的API,发现MultiThreadedHttpConnectionManager是API 2.0中的类,而ThreadSafeClientConnManager是API 4.0中的类,比前者更新,所以选择使用ThreadSafeClientConnManager。另外,还看到有PoolingClientConnectionManager这个类,是API 4.2中的类,比ThreadSafeClientConnManager更新,但Android SDK中找不到该类。所以目前还是选择了ThreadSafeClientConnManager进行管理)


1)大量传输数据时,使用“请求流/响应流”的方式
    当需要传输大量数据时,不应使用字符串(strings)或者字节数组(byte arrays),因为它们会将数据缓存至内存。当数据过多,尤其在多线程情况下,很容易造成内存溢出(out of memory,OOM)。
    而HttpClient能够有效处理“实体流(stream)”。这些“流”不会缓存至内存、而会直接进行数据传输。采用“请求流/响应流”的方式进行传输,可以减少内存占用,降低内存溢出的风险。
    例如:
    // Get method: getResponseBodyAsStream()
    // not use getResponseBody(), or getResponseBodyAsString()
    GetMethod httpGet = new GetMethod(url);  
    InputStream inputStream = httpGet.getResponseBodyAsStream();
    // Post method: getResponseBodyAsStream()
    PostMethod httpPost = new PostMethod(url);  
    InputStream inputStream = httpPost.getResponseBodyAsStream(); 

2)持续握手(Expect-continue handshake)
    在认证系统或其他可能遭到服务器拒绝应答的情况下(如:登陆失败),如果发送整个请求体,则会大大降低效率。此时,可以先发送部分请求(如:只发送请求头)进行试探,如果服务器愿意接收,则继续发送请求体。此项优化主要进行以下配置:
    // use expect-continue handshake
    HttpProtocolParams.setUseExpectContinue(httpParams, true);

3)“旧连接”检查(Stale connection check)
    HttpClient为了提升性能,默认采用了“重用连接”机制,即在有传输数据需求时,会首先检查连接池中是否有可供重用的连接,如果有,则会重用连接。同时,为了确保该“被重用”的连接确实有效,会在重用之前对其进行有效性检查。这个检查大概会花费15-30毫秒。关闭该检查举措,会稍微提升传输速度,但也可能出现“旧连接”过久而被服务器端关闭、从而出现I/O异常。
    关闭旧连接检查的配置为:
    // disable stale check
    HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);

 4)超时设置
    进行超时设置,让连接在超过时间后自动失效,释放占用资源。
    // timeout: get connections from connection pool
    ConnManagerParams.setTimeout(httpParams, 1000);  
    // timeout: connect to the server
    HttpConnectionParams.setConnectionTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);
    // timeout: transfer data from server
    HttpConnectionParams.setSoTimeout(httpParams, DEFAULT_SOCKET_TIMEOUT);
5)连接数限制
    配置每台主机最多连接数和连接池中的最多连接总数,对连接数量进行限制。其中,DEFAULT_HOST_CONNECTIONS和DEFAULT_MAX_CONNECTIONS是由客户端程序员根据需要而设置的。
    // set max connections per host
    ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(DEFAULT_HOST_CONNECTIONS)); 
    // set max total connections
    ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);


package com.wqry.sm.connection.http;

import java.security.KeyStore;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
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.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
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.HTTP;

import android.net.http.AndroidHttpClient;
import android.util.Log;

import com.wqry.sm.connection.net.EasySSLSocketFactory;

public class HttpConnector {

private final static int TIMEOUT = 1000;
private final static int CONNECT_TIMEOUT = 6000;
private final static int SO_TIMEOUT = 10000;

private static HttpConnector instance = new HttpConnector();
private int nThreads = 3;
private ThreadPoolExecutor sExecutorService;

// 服务器秘钥
private static KeyStore trustStore;

public static KeyStore getTrustStore() {
return trustStore;
}

public static void setTrustStore(KeyStore trustStore) {
HttpConnector.trustStore = trustStore;
}

private HttpClient httpClient;
private HttpClient httpsClient;

private HttpConnector() {
sExecutorService = (ThreadPoolExecutor) Executors
.newFixedThreadPool(nThreads);
}

public static HttpConnector getInstance() {
return instance;
}

public int getThreadsPoolSize() {
return nThreads;
}

public void setThreadsPoolSize(int size) {
nThreads = size;
sExecutorService.setMaximumPoolSize(nThreads);
sExecutorService.setCorePoolSize(nThreads);
AndroidHttpClient ahc;
}

public void sendRequest(Runnable runnable) {
sExecutorService.execute(runnable);
}

public synchronized HttpClient getHttpClient() {
if (null == httpClient) {
// 初始化工作
HttpParams params = new BasicHttpParams();

HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params,
HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);

// 设置连接管理器的超时
ConnManagerParams.setTimeout(params, TIMEOUT);

// 设置连接超时
HttpConnectionParams.setConnectionTimeout(params, CONNECT_TIMEOUT);

// 设置Socket超时
HttpConnectionParams.setSoTimeout(params, SO_TIMEOUT);

SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", SSLSocketFactory
.getSocketFactory(), 80));

ClientConnectionManager cOnnManager= new ThreadSafeClientConnManager(
params, schemeRegistry);

httpClient = new DefaultHttpClient(connManager, params);
}

return httpClient;
}

public synchronized HttpClient getHttpsClient() {
if (null == httpsClient) {
// 初始化工作
HttpParams params = new BasicHttpParams();

HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params,
HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);

// 设置连接管理器的超时
ConnManagerParams.setTimeout(params, TIMEOUT);

// 设置连接超时
HttpConnectionParams.setConnectionTimeout(params, CONNECT_TIMEOUT);

// 设置Socket超时
HttpConnectionParams.setSoTimeout(params, SO_TIMEOUT);

SchemeRegistry schemeRegistry = new SchemeRegistry();

schemeRegistry.register(new Scheme("http",
new EasySSLSocketFactory(), 80));
try {
schemeRegistry.register(new Scheme("https",
new SSLSocketFactory(trustStore), 443));
} catch (Exception e) {
Log.e("HttpRequest", "getHttpsClient.register.Exception", e);
schemeRegistry.register(new Scheme("https",
new EasySSLSocketFactory(), 443));
}
// schemeRegistry.register(new Scheme("http", PlainSocketFactory
// .getSocketFactory(), 80));
// schemeRegistry.register(new Scheme("https", SSLSocketFactory
// .getSocketFactory(), 80));

ClientConnectionManager cOnnManager= new ThreadSafeClientConnManager(
params, schemeRegistry);

httpsClient = new DefaultHttpClient(connManager, params);
}

return httpsClient;
}
}


附录1:关于HttpURLConnection的优化

从Android官网上看到一点,整理如下:

    1)上传数据至服务器时(即:向服务器发送请求),如果知道上传数据的大小,应该显式使用setFixedLengthStreamingMode(int)来设置上传数据的精确值;如果不知道上传数据的大小,则应使用setChunkedStreamingMode(int)——通常使用默认值“0”作为实际参数传入。如果两个函数都未设置,则系统会强制将“请求体”中的所有内容都缓存至内存中(在通过网络进行传输之前),这样会浪费“堆”内存(甚至可能耗尽),并加重隐患。

    2)如果通过流(stream)输入或输出少量数据,则需要使用带缓冲区的流(如BufferedInputStream);大量读取或输出数据时,可忽略缓冲流(不使用缓冲流会增加磁盘I/O,默认的流操作是直接进行磁盘I/O的);

    3)当需要传输(输入或输出)大量数据时,使用“流”来限制内存中的数据量——即:将数据直接放在“流”中,而不是存储在字节数组或字符串中(这些都存储在内存中)。



附录2:Android提供的AndroidHttpClient类

AndroidHttpClient继承自HttpClient,并且使用了ClientConnectionManager进行线程池管理

AndroidHttpClient和DefaultHttpClient的区别: 
AndroidHttpClient不能在主线程中execute,会抛出异常。
AndroidHttpClient通过静态方法newInstance获得实例,参数是代理,不用代理的话填“”。
DefaultHttpClient默认是启用COOKIE的,AndroidHttpClient默认不启用COOKIE,
要使用的话每次execute时要加一个HttpContext参数,并且添加COOKIEStore。用完后别忘了close不然不能创建新实例。

源码:

/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package android.net.http;

import com.android.internal.http.HttpDateTime;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.entity.AbstractHttpEntity;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ClientConnectionManager;
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.DefaultHttpClient;
import org.apache.http.impl.client.RequestWrapper;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
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.BasicHttpProcessor;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.BasicHttpContext;

import java.io.IOException;
import java.io.InputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.net.URI;

import android.content.Context;
import android.content.ContentResolver;
import android.net.SSLCertificateSocketFactory;
import android.net.SSLSessionCache;
import android.os.Looper;
import android.util.Base64;
import android.util.Log;

/**
* Implementation of the Apache {@link DefaultHttpClient} that is configured with
* reasonable default settings and registered schemes for Android, and
* also lets the user add {@link HttpRequestInterceptor} classes.
* Don't create this directly, use the {@link #newInstance} factory method.
*
*

This client processes COOKIEs but does not retain them by default.
* To retain COOKIEs, simply add a COOKIE store to the HttpContext:


*
*
context.setAttribute(ClientContext.COOKIE_STORE, COOKIEStore);

*/
public final class AndroidHttpClient implements HttpClient {

// Gzip of data shorter than this probably won't be worthwhile
public static long DEFAULT_SYNC_MIN_GZIP_BYTES = 256;

// Default connection and socket timeout of 60 seconds. Tweak to taste.
private static final int SOCKET_OPERATION_TIMEOUT = 60 * 1000;

private static final String TAG = "AndroidHttpClient";

private static String[] textCOntentTypes= new String[] {
"text/",
"application/xml",
"application/json"
};

/** Interceptor throws an exception if the executing thread is blocked */
private static final HttpRequestInterceptor sThreadCheckInterceptor =
new HttpRequestInterceptor() {
public void process(HttpRequest request, HttpContext context) {
// Prevent the HttpRequest from being sent on the main thread
if (Looper.myLooper() != null && Looper.myLooper() == Looper.getMainLooper() ) {
throw new RuntimeException("This thread forbids HTTP requests");
}
}
};

/**
* Create a new HttpClient with reasonable defaults (which you can update).
*
* @param userAgent to report in your HTTP requests
* @param context to use for caching SSL sessions (may be null for no caching)
* @return AndroidHttpClient for you to use for all your requests.
*/
public static AndroidHttpClient newInstance(String userAgent, Context context) {
HttpParams params = new BasicHttpParams();

// Turn off stale checking. Our connections break all the time anyway,
// and it's not worth it to pay the penalty of checking every time.
HttpConnectionParams.setStaleCheckingEnabled(params, false);

HttpConnectionParams.setConnectionTimeout(params, SOCKET_OPERATION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, SOCKET_OPERATION_TIMEOUT);
HttpConnectionParams.setSocketBufferSize(params, 8192);

// Don't handle redirects -- return them to the caller. Our code
// often wants to re-POST after a redirect, which we must do ourselves.
HttpClientParams.setRedirecting(params, false);

// Use a session cache for SSL sockets
SSLSessionCache sessiOnCache= cOntext== null ? null : new SSLSessionCache(context);

// Set the specified user agent and register standard protocols.
HttpProtocolParams.setUserAgent(params, userAgent);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http",
PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https",
SSLCertificateSocketFactory.getHttpSocketFactory(
SOCKET_OPERATION_TIMEOUT, sessionCache), 443));

ClientConnectionManager manager =
new ThreadSafeClientConnManager(params, schemeRegistry);

// We use a factory method to modify superclass initialization
// parameters without the funny call-a-static-method dance.
return new AndroidHttpClient(manager, params);
}

/**
* Create a new HttpClient with reasonable defaults (which you can update).
* @param userAgent to report in your HTTP requests.
* @return AndroidHttpClient for you to use for all your requests.
*/
public static AndroidHttpClient newInstance(String userAgent) {
return newInstance(userAgent, null /* session cache */);
}

private final HttpClient delegate;

private RuntimeException mLeakedException = new IllegalStateException(
"AndroidHttpClient created and never closed");

private AndroidHttpClient(ClientConnectionManager ccm, HttpParams params) {
this.delegate = new DefaultHttpClient(ccm, params) {
@Override
protected BasicHttpProcessor createHttpProcessor() {
// Add interceptor to prevent making requests from main thread.
BasicHttpProcessor processor = super.createHttpProcessor();
processor.addRequestInterceptor(sThreadCheckInterceptor);
processor.addRequestInterceptor(new CurlLogger());

return processor;
}

@Override
protected HttpContext createHttpContext() {
// Same as DefaultHttpClient.createHttpContext() minus the
// COOKIE store.
HttpContext cOntext= new BasicHttpContext();
context.setAttribute(
ClientContext.AUTHSCHEME_REGISTRY,
getAuthSchemes());
context.setAttribute(
ClientContext.COOKIESPEC_REGISTRY,
getCOOKIESpecs());
context.setAttribute(
ClientContext.CREDS_PROVIDER,
getCredentialsProvider());
return context;
}
};
}

@Override
protected void finalize() throws Throwable {
super.finalize();
if (mLeakedException != null) {
Log.e(TAG, "Leak found", mLeakedException);
mLeakedException = null;
}
}

/**
* Modifies a request to indicate to the server that we would like a
* gzipped response. (Uses the "Accept-Encoding" HTTP header.)
* @param request the request to modify
* @see #getUngzippedContent
*/
public static void modifyRequestToAcceptGzipResponse(HttpRequest request) {
request.addHeader("Accept-Encoding", "gzip");
}

/**
* Gets the input stream from a response entity. If the entity is gzipped
* then this will get a stream over the uncompressed data.
*
* @param entity the entity whose content should be read
* @return the input stream to read from
* @throws IOException
*/
public static InputStream getUngzippedContent(HttpEntity entity)
throws IOException {
InputStream respOnseStream= entity.getContent();
if (respOnseStream== null) return responseStream;
Header header = entity.getContentEncoding();
if (header == null) return responseStream;
String cOntentEncoding= header.getValue();
if (cOntentEncoding== null) return responseStream;
if (contentEncoding.contains("gzip")) responseStream
= new GZIPInputStream(responseStream);
return responseStream;
}

/**
* Release resources associated with this client. You must call this,
* or significant resources (sockets and memory) may be leaked.
*/
public void close() {
if (mLeakedException != null) {
getConnectionManager().shutdown();
mLeakedException = null;
}
}

public HttpParams getParams() {
return delegate.getParams();
}

public ClientConnectionManager getConnectionManager() {
return delegate.getConnectionManager();
}

public HttpResponse execute(HttpUriRequest request) throws IOException {
return delegate.execute(request);
}

public HttpResponse execute(HttpUriRequest request, HttpContext context)
throws IOException {
return delegate.execute(request, context);
}

public HttpResponse execute(HttpHost target, HttpRequest request)
throws IOException {
return delegate.execute(target, request);
}

public HttpResponse execute(HttpHost target, HttpRequest request,
HttpContext context) throws IOException {
return delegate.execute(target, request, context);
}

public T execute(HttpUriRequest request,
ResponseHandler responseHandler)
throws IOException, ClientProtocolException {
return delegate.execute(request, responseHandler);
}

public T execute(HttpUriRequest request,
ResponseHandler responseHandler, HttpContext context)
throws IOException, ClientProtocolException {
return delegate.execute(request, responseHandler, context);
}

public T execute(HttpHost target, HttpRequest request,
ResponseHandler responseHandler) throws IOException,
ClientProtocolException {
return delegate.execute(target, request, responseHandler);
}

public T execute(HttpHost target, HttpRequest request,
ResponseHandler responseHandler, HttpContext context)
throws IOException, ClientProtocolException {
return delegate.execute(target, request, responseHandler, context);
}

/**
* Compress data to send to server.
* Creates a Http Entity holding the gzipped data.
* The data will not be compressed if it is too short.
* @param data The bytes to compress
* @return Entity holding the data
*/
public static AbstractHttpEntity getCompressedEntity(byte data[], ContentResolver resolver)
throws IOException {
AbstractHttpEntity entity;
if (data.length entity = new ByteArrayEntity(data);
} else {
ByteArrayOutputStream arr = new ByteArrayOutputStream();
OutputStream zipper = new GZIPOutputStream(arr);
zipper.write(data);
zipper.close();
entity = new ByteArrayEntity(arr.toByteArray());
entity.setContentEncoding("gzip");
}
return entity;
}

/**
* Retrieves the minimum size for compressing data.
* Shorter data will not be compressed.
*/
public static long getMinGzipSize(ContentResolver resolver) {
return DEFAULT_SYNC_MIN_GZIP_BYTES; // For now, this is just a constant.
}

/* cURL logging support. */

/**
* Logging tag and level.
*/
private static class LoggingConfiguration {

private final String tag;
private final int level;

private LoggingConfiguration(String tag, int level) {
this.tag = tag;
this.level = level;
}

/**
* Returns true if logging is turned on for this configuration.
*/
private boolean isLoggable() {
return Log.isLoggable(tag, level);
}

/**
* Prints a message using this configuration.
*/
private void println(String message) {
Log.println(level, tag, message);
}
}

/** cURL logging configuration. */
private volatile LoggingConfiguration curlConfiguration;

/**
* Enables cURL request logging for this client.
*
* @param name to log messages with
* @param level at which to log messages (see {@link android.util.Log})
*/
public void enableCurlLogging(String name, int level) {
if (name == null) {
throw new NullPointerException("name");
}
if (level Log.ASSERT) {
throw new IllegalArgumentException("Level is out of range ["
+ Log.VERBOSE + ".." + Log.ASSERT + "]");
}

curlCOnfiguration= new LoggingConfiguration(name, level);
}

/**
* Disables cURL logging for this client.
*/
public void disableCurlLogging() {
curlCOnfiguration= null;
}

/**
* Logs cURL commands equivalent to requests.
*/
private class CurlLogger implements HttpRequestInterceptor {
public void process(HttpRequest request, HttpContext context)
throws HttpException, IOException {
LoggingConfiguration cOnfiguration= curlConfiguration;
if (configuration != null
&& configuration.isLoggable()
&& request instanceof HttpUriRequest) {
// Never print auth token -- we used to check ro.secure=0 to
// enable that, but can't do that in unbundled code.
configuration.println(toCurl((HttpUriRequest) request, false));
}
}
}

/**
* Generates a cURL command equivalent to the given request.
*/
private static String toCurl(HttpUriRequest request, boolean logAuthToken) throws IOException {
StringBuilder builder = new StringBuilder();

builder.append("curl ");

for (Header header: request.getAllHeaders()) {
if (!logAuthToken
&& (header.getName().equals("Authorization") ||
header.getName().equals("COOKIE"))) {
continue;
}
builder.append("--header \"");
builder.append(header.toString().trim());
builder.append("\" ");
}

URI uri = request.getURI();

// If this is a wrapped request, use the URI from the original
// request instead. getURI() on the wrapper seems to return a
// relative URI. We want an absolute URI.
if (request instanceof RequestWrapper) {
HttpRequest original = ((RequestWrapper) request).getOriginal();
if (original instanceof HttpUriRequest) {
uri = ((HttpUriRequest) original).getURI();
}
}

builder.append("\"");
builder.append(uri);
builder.append("\"");

if (request instanceof HttpEntityEnclosingRequest) {
HttpEntityEnclosingRequest entityRequest =
(HttpEntityEnclosingRequest) request;
HttpEntity entity = entityRequest.getEntity();
if (entity != null && entity.isRepeatable()) {
if (entity.getContentLength() <1024) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
entity.writeTo(stream);

if (isBinaryContent(request)) {
String base64 = Base64.encodeToString(stream.toByteArray(), Base64.NO_WRAP);
builder.insert(0, "echo '" + base64 + "' | base64 -d > /tmp/$$.bin; ");
builder.append(" --data-binary @/tmp/$$.bin");
} else {
String entityString = stream.toString();
builder.append(" --data-ascii \"")
.append(entityString)
.append("\"");
}
} else {
builder.append(" [TOO MUCH DATA TO INCLUDE]");
}
}
}

return builder.toString();
}

private static boolean isBinaryContent(HttpUriRequest request) {
Header[] headers;
headers = request.getHeaders(Headers.CONTENT_ENCODING);
if (headers != null) {
for (Header header : headers) {
if ("gzip".equalsIgnoreCase(header.getValue())) {
return true;
}
}
}

headers = request.getHeaders(Headers.CONTENT_TYPE);
if (headers != null) {
for (Header header : headers) {
for (String contentType : textContentTypes) {
if (header.getValue().startsWith(contentType)) {
return false;
}
}
}
}
return true;
}

/**
* Returns the date of the given HTTP date string. This method can identify
* and parse the date formats emitted by common HTTP servers, such as
* RFC 822,
* RFC 850,
* RFC 1036,
* RFC 1123 and
* ANSI
* C's asctime()
.
*
* @return the number of milliseconds since Jan. 1, 1970, midnight GMT.
* @throws IllegalArgumentException if {@code dateString} is not a date or
* of an unsupported format.
*/
public static long parseDate(String dateString) {
return HttpDateTime.parse(dateString);
}
}



推荐阅读
  • H5技术实现经典游戏《贪吃蛇》
    本文将分享一个使用HTML5技术实现的经典小游戏——《贪吃蛇》。通过H5技术,我们将探讨如何构建这款游戏的两种主要玩法:积分闯关和无尽模式。 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 本文介绍了SIP(Session Initiation Protocol,会话发起协议)的基本概念、功能、消息格式及其实现机制。SIP是一种在IP网络上用于建立、管理和终止多媒体通信会话的应用层协议。 ... [详细]
  • 如何高效学习鸿蒙操作系统:开发者指南
    本文探讨了开发者如何更有效地学习鸿蒙操作系统,提供了来自行业专家的建议,包括系统化学习方法、职业规划建议以及具体的开发技巧。 ... [详细]
  • 本文由chszs撰写,详细介绍了Apache Mina框架的核心开发流程及自定义协议处理方法。文章涵盖从创建IoService实例到协议编解码的具体步骤,适合希望深入了解Mina框架应用的开发者。 ... [详细]
  • Canopy环境安装与使用指南
    《利用Python进行数据分析》一书推荐使用EPDFree版本的环境,然而随着技术的发展,目前更多人倾向于使用Canopy。本文将详细介绍Canopy的安装及使用方法。 ... [详细]
  • Spring Security基础配置详解
    本文详细介绍了Spring Security的基础配置方法,包括如何搭建Maven多模块工程以及具体的安全配置步骤,帮助开发者更好地理解和应用这一强大的安全框架。 ... [详细]
  • 视觉Transformer综述
    本文综述了视觉Transformer在计算机视觉领域的应用,从原始Transformer出发,详细介绍了其在图像分类、目标检测和图像分割等任务中的最新进展。文章不仅涵盖了基础的Transformer架构,还深入探讨了各类增强版Transformer模型的设计思路和技术细节。 ... [详细]
  • Asynchronous JavaScript and XML (AJAX) 的流行很大程度上得益于 Google 在其产品如 Google Suggest 和 Google Maps 中的应用。本文将深入探讨 AJAX 在 .NET 环境下的工作原理及其实现方法。 ... [详细]
  • 在Android中实现黑客帝国风格的数字雨效果
    本文将详细介绍如何在Android平台上利用自定义View实现类似《黑客帝国》中的数字雨效果。通过实例代码,我们将探讨如何设置文字颜色、大小,以及如何控制数字下落的速度和间隔。 ... [详细]
  • 本文探讨了如何在PHP与MySQL环境中实现高效的分页查询,包括基本的分页实现、性能优化技巧以及高级的分页策略。 ... [详细]
  • 本文是对《敏捷软件开发:原则、模式与实践》一书的深度解析,书中不仅探讨了敏捷方法的核心理念及其应用,还详细介绍了面向对象设计的原则、设计模式的应用技巧及UML的有效使用。 ... [详细]
  • Docker安全策略与管理
    本文探讨了Docker的安全挑战、核心安全特性及其管理策略,旨在帮助读者深入理解Docker安全机制,并提供实用的安全管理建议。 ... [详细]
  • Beetl是一款先进的Java模板引擎,以其丰富的功能、直观的语法、卓越的性能和易于维护的特点著称。它不仅适用于高响应需求的大型网站,也适合功能复杂的CMS管理系统,提供了一种全新的模板开发体验。 ... [详细]
  • 本文介绍了如何通过C#语言调用动态链接库(DLL)中的函数来实现IC卡的基本操作,包括初始化设备、设置密码模式、获取设备状态等,并详细展示了将TextBox中的数据写入IC卡的具体实现方法。 ... [详细]
author-avatar
火立者
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有