HttpUtils
模块的底层是使用的HttpClient
。
HttpUtils
模块支持Restful
风格的四种请求方式(GET
、POST
、PUT
、DELETE
)。
下面是在HttpUtils
模块基础上封装的接口:
package com.fpliu.newton.framework.net;
import android.text.TextUtils;
import com.fpliu.newton.framework.util.DebugLog;
import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.http.HttpHandler;
import com.lidroid.xutils.http.RequestParams;
import com.lidroid.xutils.http.callback.RequestCallBack;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
/**
* 网络请求 - 使用XUtils开源库
* https://github.com/leleliu008/xutils
* 支持Restful API的GET、POST、PUT、DELETE四种方式
*
* @author 792793182@qq.com 2015-06-15
*/
public final class XUtilsRequest {
private static final String TAG = XUtilsRequest.class.getSimpleName();
/**
* 请求头
*/
private static final String HEADER_ACCEPT = "Accept";
private static final String HEADER_CONNECTION = "Connection";
private static final String HEADER_AUTHORIZATION = "Authorization";
private static final String HEADER_USER_AGENT = "User-Agent";
private static final String HEADER_REFERER = "Referer";
private static final String HEADER_CONTENT_TYPE = "Content-Type";
/**
* 请求体格式 - 表单
*/
private static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded";
/**
* 请求体格式 - JSON
*/
private static final String CONTENT_TYPE_JSON = "application/json";
/**
* 请求体格式 - XML
*/
private static final String CONTENT_TYPE_XML = "application/xml";
private static final CookieStore cookieStore = new BasicCookieStore();
private XUtilsRequest() {
}
/**
* 下载
*
* @param url 资源路径
* @param desFilePath 本地路径
* @param requestCallBack 请求回调
*/
public static void asyncDownload(String url, String desFilePath, RequestCallBack<File> requestCallBack) {
RequestParams requestParams = new RequestParams();
HttpUtils http = newHttpUtils(requestParams, url, "");
HttpHandler handler = http.download(url,
desFilePath,
requestParams,
true, // 如果目标文件存在,接着未完成的部分继续下载。服务器不支持RANGE时将从新下载。
false,
requestCallBack);
}
/**
* GET请求
*
* @param url 请求资源的路径
* @param authorization 验证用户,不需要验证的,传入空,即可
* @param params URL的参数
* @param callback 请求的回调
*/
public static <K> void asyncGet(String url, String authorization, List<BasicNameValuePair> params, RequestCallBack<K> callback) {
RequestParams requestParams = new RequestParams();
url = getUrl(url, params);
HttpUtils httpUtils = newHttpUtils(requestParams, url, authorization);
httpUtils.send(com.lidroid.xutils.http.client.HttpRequest.HttpMethod.GET, url, requestParams, callback);
}
/**
* POST请求,请求体是表单,是异步请求
*
* @param url 请求资源的路径
* @param authorization 验证用户,不需要验证的,传入空,即可
* @param params 请求参数
* @param callback 请求的回调
*/
public static <K> void asyncPostForm(String url, String authorization, List<BasicNameValuePair> params, RequestCallBack<K> callback) {
RequestParams requestParams = new RequestParams();
requestParams.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_FORM);
requestParams.setBodyEntity(getFormEntity(params));
HttpUtils httpUtils = newHttpUtils(requestParams, url, authorization);
httpUtils.send(com.lidroid.xutils.http.client.HttpRequest.HttpMethod.POST, url, requestParams, callback);
}
/**
* POST请求,请求体是表单,是异步请求
*
* @param url 请求资源的路径
* @param authorization 验证用户,不需要验证的,传入空,即可
* @param params 请求参数
* @param callback 请求的回调
*/
public static <K> void asyncPostForm(String url, String authorization, RequestCallBack<K> callback, String... params) {
RequestParams requestParams = new RequestParams();
requestParams.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_FORM);
requestParams.setBodyEntity(getFormEntity(params));
HttpUtils httpUtils = newHttpUtils(requestParams, url, authorization);
httpUtils.send(com.lidroid.xutils.http.client.HttpRequest.HttpMethod.POST, url, requestParams, callback);
}
/**
* POST请求,请求体是JSON,是异步请求
*
* @param url 请求资源的路径
* @param authorization 验证用户,不需要验证的,传入空,即可
* @param json JSON字符串,使用String类型可以支持GSON、fastJson、json-lib等库的转化,而不局限于一种
* @param callback 请求的回调
*/
public static <K> void asyncPostJson(String url, String authorization, String json, RequestCallBack<K> callback) {
RequestParams requestParams = new RequestParams();
requestParams.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_JSON);
requestParams.setBodyEntity(getStringEntity(json, CONTENT_TYPE_JSON));
HttpUtils httpUtils = newHttpUtils(requestParams, url, authorization);
httpUtils.send(com.lidroid.xutils.http.client.HttpRequest.HttpMethod.POST, url, requestParams, callback);
}
/**
* POST请求,请求体是XML,是异步请求
*
* @param url 请求资源的路径
* @param authorization 验证用户,不需要验证的,传入空,即可
* @param xml XML字符串
* @param callback 请求的回调
*/
public static <K> void asyncPostXml(String url, String authorization, String xml, RequestCallBack<K> callback) {
RequestParams requestParams = new RequestParams();
requestParams.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_XML);
requestParams.setBodyEntity(getStringEntity(xml, CONTENT_TYPE_XML));
HttpUtils httpUtils = newHttpUtils(requestParams, url, authorization);
httpUtils.send(com.lidroid.xutils.http.client.HttpRequest.HttpMethod.POST, url, requestParams, callback);
}
/**
* PUT请求,请求体是表单,是异步请求
*
* @param url 请求资源的路径
* @param authorization 验证用户,不需要验证的,传入空,即可
* @param params 请求参数对,语法糖
* @param callback 请求的回调
*/
public static <K> void asyncPutForm(String url, String authorization, List<BasicNameValuePair> params, RequestCallBack<K> callback) {
RequestParams requestParams = new RequestParams();
requestParams.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_FORM);
requestParams.setBodyEntity(getFormEntity(params));
HttpUtils httpUtils = newHttpUtils(requestParams, url, authorization);
httpUtils.send(com.lidroid.xutils.http.client.HttpRequest.HttpMethod.PUT, url, requestParams, callback);
}
/**
* PUT请求,请求体是表单,是异步请求
*
* @param url 请求资源的路径
* @param authorization 验证用户,不需要验证的,传入空,即可
* @param params 请求参数
* @param callback 请求的回调
*/
public static <K> void asyncPutForm(String url, String authorization, RequestCallBack<K> callback, String... params) {
RequestParams requestParams = new RequestParams();
requestParams.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_FORM);
requestParams.setBodyEntity(getFormEntity(params));
HttpUtils httpUtils = newHttpUtils(requestParams, url, authorization);
httpUtils.send(com.lidroid.xutils.http.client.HttpRequest.HttpMethod.PUT, url, requestParams, callback);
}
/**
* PUT请求,请求体是JSON,是异步请求
*
* @param url 请求资源的路径
* @param authorization 验证用户,不需要验证的,传入空,即可
* @param json JSON字符串,使用String类型可以支持GSON、fastJson、json-lib等库的转化,而不局限于一种
* @param callback 请求的回调
*/
public static <K> void asyncPutJson(String url, String authorization, String json, RequestCallBack<K> callback) {
RequestParams requestParams = new RequestParams();
requestParams.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_JSON);
requestParams.setBodyEntity(getStringEntity(json, CONTENT_TYPE_JSON));
HttpUtils httpUtils = newHttpUtils(requestParams, url, authorization);
httpUtils.send(com.lidroid.xutils.http.client.HttpRequest.HttpMethod.PUT, url, requestParams, callback);
}
/**
* PUT请求,请求体是XML,是异步请求
*
* @param url 请求资源的路径
* @param authorization 验证用户,不需要验证的,传入空,即可
* @param xml XML字符串
* @param callback 请求的回调
*/
public static <K> void asyncPutXml(String url, String authorization, String xml, RequestCallBack<K> callback) {
RequestParams requestParams = new RequestParams();
requestParams.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_XML);
requestParams.setBodyEntity(getStringEntity(xml, CONTENT_TYPE_XML));
HttpUtils httpUtils = newHttpUtils(requestParams, url, authorization);
httpUtils.send(com.lidroid.xutils.http.client.HttpRequest.HttpMethod.PUT, url, requestParams, callback);
}
/**
* DELETE请求
*
* @param url 请求资源的路径
* @param authorization 验证用户,不需要验证的,传入空,即可
* @param params URL的参数
* @param callback 请求的回调
*/
public static <K> void asyncDelete(String url, String authorization, List<BasicNameValuePair> params, RequestCallBack<K> callback) {
RequestParams requestParams = new RequestParams();
url = getUrl(url, params);
HttpUtils httpUtils = newHttpUtils(requestParams, url, authorization);
httpUtils.send(com.lidroid.xutils.http.client.HttpRequest.HttpMethod.DELETE, url, requestParams, callback);
}
/**
* 组装URL
*
* @param url
* @param params
* @return
*/
private static String getUrl(String url, List<BasicNameValuePair> params) {
String urlParams = "";
if (params != null && !params.isEmpty()) {
urlParams = URLEncodedUtils.format(params, "UTF-8");
}
if (!TextUtils.isEmpty(urlParams)) {
url += "?" + urlParams;
}
return url;
}
public static UrlEncodedFormEntity getFormEntity(String... kvs) {
if (kvs != null) {
int length = kvs.length / 2;
if (length > 0) {
ArrayList<BasicNameValuePair> nvs = new ArrayList<BasicNameValuePair>(length);
for (int i = 0; i < length; i += 2) {
//如果Key为空,就跳过
if (TextUtils.isEmpty(kvs[i])) {
continue;
}
nvs.add(new BasicNameValuePair(kvs[i], kvs[i + 1]));
}
if (!nvs.isEmpty()) {
return getFormEntity(nvs);
}
}
}
return null;
}
/**
* 获取表单实体
*
* @param params
* @return
*/
public static UrlEncodedFormEntity getFormEntity(List<BasicNameValuePair> params) {
UrlEncodedFormEntity entity = null;
try {
entity = new UrlEncodedFormEntity(params, HTTP.UTF_8);
} catch (UnsupportedEncodingException e) {
DebugLog.e(TAG, "getFormEntity()", e);
}
return entity;
}
/**
* 获取字符串类型的请求体
*
* @param str
* @param contentType
* @return
*/
private static StringEntity getStringEntity(String str, String contentType) {
StringEntity stringEntity = null;
try {
stringEntity = new StringEntity(str, HTTP.UTF_8);
stringEntity.setContentType(contentType);
} catch (UnsupportedEncodingException e) {
DebugLog.e(TAG, "getStringEntity()", e);
}
return stringEntity;
}
/**
* POST请求
*
* @param url
* @param contentHeader
* @param entity
* @param callback
* @return
*/
private static <K> void post(String url, String contentHeader, String authorization, HttpEntity entity, RequestCallBack<K> callback) {
RequestParams requestParams = new RequestParams();
requestParams.setHeader(HEADER_CONTENT_TYPE, contentHeader);
requestParams.setBodyEntity(entity);
HttpUtils httpUtils = newHttpUtils(requestParams, url, authorization);
httpUtils.send(com.lidroid.xutils.http.client.HttpRequest.HttpMethod.POST, url, requestParams, callback);
}
public static HttpUtils newHttpUtils(RequestParams requestParams, final String url, String authorization) {
if (!TextUtils.isEmpty(authorization)) {
requestParams.setHeader(HEADER_AUTHORIZATION, authorization);
}
HttpUtils httpUtils = new HttpUtils();
httpUtils.configUserAgent("Android");
// 设置重试次数
httpUtils.configRequestRetryCount(3);
httpUtils.configResponseTextCharset("UTF-8");
// 设超时时间
httpUtils.configTimeout(3 * 1000);
// 设置缓存存活时间为10秒
httpUtils.configCurrentHttpCacheExpiry(10 * 1000);
//配置Cookie的保存
httpUtils.configCookieStore(cookieStore);
DefaultHttpClient httpClient = (DefaultHttpClient) httpUtils.getHttpClient();
// 拦截请求,打印日志
httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
@Override
public void process(HttpRequest httpRequest, HttpContext httpContext)
throws org.apache.http.HttpException, IOException {
DebugLog.d(TAG, HTTPUtil.getRequestInfo(httpRequest));
}
});
// 拦截响应,打印日志
httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
@Override
public void process(HttpResponse response, HttpContext httpContext)
throws org.apache.http.HttpException, IOException {
// 看看有没有Content-Type头
Header[] headers = response.getHeaders("Content-Type");
if (headers == null || headers.length == 0) {
DebugLog.d(TAG, HTTPUtil.getResponseInfo(response, url, ""));
return;
}
String contentType = headers[0].getValue();
if (contentType.contains("application/x-www-form-urlencoded")
|| contentType.contains("application/json")
|| contentType.contains("application/xml")
|| contentType.contains("text/html")) {
// 看看有没有返回实体
HttpEntity entity = response.getEntity();
if (entity == null) {
DebugLog.d(TAG, HTTPUtil.getResponseInfo(response, url, ""));
return;
}
String entityStr = "";
try {
entityStr = EntityUtils.toString(entity);
} catch (Exception e) {
DebugLog.e(TAG, "", e);
}
DebugLog.d(TAG, HTTPUtil.getResponseInfo(response, url, entityStr));
// 如果这个实体是不可重用的,就重新设置一下
if (!entity.isRepeatable()) {
response.setEntity(new StringEntity(entityStr, "utf-8"));
}
} else {
DebugLog.d(TAG, HTTPUtil.getResponseInfo(response, url, ""));
}
}
});
return httpUtils;
}
}
HttpUtils
模块本身有一个缺点,就是他没有打印任何的日志, 我们想要观察Http
请求和响应过程,就必须自己打印日志。 原理是:注册Http
请求的拦截器和Http
响应的拦截器。打印相关的日志。
下面是打印日志的实现代码:
HttpUtils httpUtils = new HttpUtils();
DefaultHttpClient httpClient = (DefaultHttpClient) httpUtils.getHttpClient();
// 拦截请求,打印日志
httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
@Override
public void process(HttpRequest httpRequest, HttpContext httpContext)
throws org.apache.http.HttpException, IOException {
DebugLog.d(TAG, HTTPUtil.getRequestInfo(httpRequest));
}
});
// 拦截响应,打印日志
httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
@Override
public void process(HttpResponse response, HttpContext httpContext)
throws org.apache.http.HttpException, IOException {
// 看看有没有Content-Type头
Header[] headers = response.getHeaders("Content-Type");
if (headers == null || headers.length == 0) {
DebugLog.d(TAG, HTTPUtil.getResponseInfo(response, url, ""));
return;
}
String contentType = headers[0].getValue();
if (contentType.contains("application/x-www-form-urlencoded")
|| contentType.contains("application/json")
|| contentType.contains("application/xml")
|| contentType.contains("text/html")) {
// 看看有没有返回实体
HttpEntity entity = response.getEntity();
if (entity == null) {
DebugLog.d(TAG, HTTPUtil.getResponseInfo(response, url, ""));
return;
}
String entityStr = "";
try {
entityStr = EntityUtils.toString(entity);
} catch (Exception e) {
DebugLog.e(TAG, "", e);
}
DebugLog.d(TAG, HTTPUtil.getResponseInfo(response, url, entityStr));
// 如果这个实体是不可重用的,就重新设置一下
if (!entity.isRepeatable()) {
response.setEntity(new StringEntity(entityStr, "utf-8"));
}
} else {
DebugLog.d(TAG, HTTPUtil.getResponseInfo(response, url, ""));
}
}
});
HTTPUtil.java
的内容如下:
package com.fpliu.newton.framework.net;
import android.text.TextUtils;
import com.lidroid.xutils.http.client.multipart.MultipartEntity;
import com.fpliu.newton.framework.util.DebugLog;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.util.EntityUtils;
public final class HTTPUtil {
private static final String TAG = HTTPUtil.class.getSimpleName();
private HTTPUtil() {
}
/**
* 获取请求信息
*
* @param httpRequest HTTP请求
* @return HTTP协议内容
*/
public static String getRequestInfo(HttpRequest httpRequest) {
StringBuilder builder = new StringBuilder("\n----------------------- request start ------------------------\n");
//请求行
builder.append(httpRequest.getRequestLine()).append('\n');
//请求头
for (Header header : httpRequest.getAllHeaders()) {
builder.append(header.getName()).append(':').append(header.getValue()).append('\n');
}
if (httpRequest instanceof HttpPost) {
//空行
builder.append('\n');
//请求体
HttpEntity httpEntity = ((HttpPost) httpRequest).getEntity();
if (httpEntity instanceof MultipartEntity) {
MultipartEntity multipartEntity = (MultipartEntity) httpEntity;
builder.append(multipartEntity);
} else {
try {
builder.append(EntityUtils.toString(httpEntity));
} catch (Exception e) {
DebugLog.e(TAG, "getRequestInfo()", e);
}
}
builder.append("\n----------------------- request end ------------------------\n");
}
return builder.toString();
}
/**
* 获取响应信息
*
* @param response 响应
* @return HTTP协议内容
*/
public static String getResponseInfo(HttpResponse response, String url, String entity) {
StringBuilder builder = new StringBuilder("\n----------------------- response start ------------------------\n");
builder.append("url:" + url + "\n");
//状态行
builder.append(response.getStatusLine()).append('\n');
//响应头
for (Header header : response.getAllHeaders()) {
builder.append(header.getName()).append(':').append(header.getValue()).append('\n');
}
//空行
builder.append('\n');
//响应体
builder.append(entity);
builder.append("\n----------------------- response end ------------------------\n");
return builder.toString();
}
}
HttpUtils
模块本身还有一个缺点,就是他没有提供对数据解析的接口, 这一点做的最好的应该是AQuery。