用过了现有的一些http
请求框架,决定自己也来简单的封装一个。本文只是基于一些http请求框架二次封装的,高手勿喷。源码
http的请求和响应
一个http的请求通常包含请求头、请求体、响应头和响应体,考虑到这些因素,HttpConfig
和 ApiResponse
就诞生了。HttpConfig
HttpConfig
http参数配置类,应该包含如下属性:
-
baseUrl/url
如果使用restful形式,baseUrl是不能为空并且url为业务path, 如果是非restful,url必须为请求全路径
-
GET/POST
有了url,接下来需要有请求的方法类型,由于我这边只用到了
GET
和POST
,所以只对此做了封装。特别说明: POST 有三种提交方式(form表单、json形式和 复杂形式)
FORM_DATA("application/x-www-form-urlencoded;charset=utf-8"),
JSON_DATA("application/json;charset=utf-8"),
MULTI_PART_DATA("multipart/form-data;charset=utf-8");
-
headers
http的请求头封装,采用
(Map<String,String>)
集合 -
params
http的请求参数,采用
(Map<String,Object>)
如果请求方法是GET
形式,那么采用拼接字符串的形式将参数拼接到url中; 如果请求方法是POST
形式,则需要根据提交参数的方式不同,会有不同的请求体。 -
cacheStrategy
考虑到App的使用交互和服务器减压,我们要考虑有一些请求可以做一些缓存,那么常用的缓存策略有
CACHE_ONLY
、CACHE_FIRST
、NET_ONLY
和NET_CACHE
-
type
type是响应数据的type,这个主要用在Http请求结果返回后将json转为bean对象的映射类型,需要考虑泛型和非泛型(Class和ParamizableType)
-
tag
给每一个请求链接打一个标签,可用于一些其它的操作,如根据tag取消请求
-
isAsync
当前请求是同步执行还是异步执行的标志,异步执行会在子线程中进行http请求,同步执行在当前线程中执行http请求。
ApiResponse
使用ApiResponse的原因是为了规范请求结果返回的表现形式,他有一个T
类型的数据。
-
code
状态码,与http请求响应状态码一致,200~300 请求成功,304 使用缓存
-
message
请求响应的错误信息
-
data
响应的数据,泛型T, 根据
httpConfig
中的type,映射 json–> bean
Http引擎
IHttpEngine是一个接口,使用者可以根据实际的情况做具体的实现。
public interface IHttpEngine {
// 开始执行 http请求
<T> execute(HttpConfig config, MultableLiveData<ApiResponse<T>> liveData);
// 根据tag取消
void cancel(Object tag);
}
由于http请求有同步和异步两种情况并且又牵扯到了缓存策略问题(如果先进行缓存返回在执行网络请求并返回数据),在异步回调的情况下这些问题可以通过回调解决,但是在同步情况下,这些问题并不能很好的处理,曾经有使用过将当前请求clone
,然后再次调用请求服务器的方法,但是在使用过jetpack
的LiveData
框架后这些问题都可以解决了。
OkhttpEngine
Android开发目前来说大多数项目使用的都是Okhttp
来做请求,本次我使用的默认引擎也是使用它来作为默认的实现。OkHttpEngine
okhttp简单配置
对okhttp进行一些简单的配置就可以进行网络请求了,如下:
- 创建okHttpClient
private static final OkHttpClient OK_HTTP_CLIENT;
// 添加日志拦截器
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OK_HTTP_CLIENT = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.addInterceptor(loggingInterceptor)
.build();
- 添加证书管理
TrustManager[] trustManagers = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
实现Http请求
IHttpEngine中的execute
方法是具体的http请求方法,所有实现IHttpEngine
的方法都需要实现此方法。
@NonNull
@Override
public <T> void execute(@NonNull Config config,
@NonNull MutableLiveData<ApiResponse<T>> liveData) {
Request request = generateRequest(config);
Call call = OK_HTTP_CLIENT.newCall(request);
if (!config.isAsync) {
execute(call, config, liveData);
} else {
enqueue(call, config, liveData);
}
}
execute
方法中大致需要做以下事:
- 创建request–> genearteRequest
- 发送http请求 —> execute/enqueue
创建httpRequest
generateRequest()
根据HttpConfig
中的请求方式来创建不同的http请求。
/**
* 根据配置信息生成request
*
* @param config 配置信息
* @return request
*/
@NonNull
private Request generateRequest(@NonNull Config config) {
switch (config.method) {
case Config.GET:
return generateGetRequest(config);
case Config.POST:
return generatePostRequest(config);
default:
throw new IllegalStateException("this request method invalidate: " + config.method);
}
}
GET请求的创建方式
genearteGetReques()
方法,利用okhttp的Request类创建request实例,并利用UrlCreator将参数拼接到url中。Url拼接时需要注意使用UrlEncoder
编码,不然可能会造成服务器和客户端解析数据不一致的情况。
/**
* 生成get方式的请求
*
* @param config 请求配置
* @return 返回get方式的request
*/
@NonNull
private Request generateGetRequest(@NonNull Config config) {
Request.Builder builder = new Request.Builder().get();
builder.tag(config.tag);
addHeader