一、网络请求抽象类
public abstract class AbstractHttpRequest {
public abstract String url();
public abstract String method();
public abstract Map<String, String> headers();
public abstract String getHeader(String key);
public abstract long cacheAge();
public abstract Object tag();
public abstract void cancel();
static abstract class AbstractBuilder{
public abstract AbstractBuilder url(String url);
public abstract AbstractBuilder method(String method);
public abstract AbstractBuilder headers(Map<String, String> headers);
public abstract AbstractBuilder query(String name, String value);
public abstract AbstractBuilder query(String name, String value, boolean encoded);
public abstract AbstractBuilder path(String path);
public abstract AbstractBuilder path(String path, boolean encoded);
public abstract AbstractBuilder addHeader(String key, String value);
public abstract AbstractBuilder cacheAge(long cacheAge);
public abstract AbstractBuilder requestBody(HttpRequestBody body);
public abstract AbstractBuilder removeHeader(String key);
public abstract AbstractBuilder tag(Object tag);
public abstract AbstractHttpRequest build();
}
}
二、网络请求实现类
public class HttpRequest extends AbstractHttpRequest {
public static final String GET = "GET";
public static final String POST = "POST";
public static final String DEL = "DEL";
public static final String PUT = "PUT";
Request request;
Call call;
@StringDef({GET,POST})
@Retention(RetentionPolicy.SOURCE)
public @interface HttpMethod{}
private HttpRequest(@NonNull Request request){
this.request = request;
}
@Override
public String url() {
if(request.url() != null){
return request.url().toString();
}else{
return "";
}
}
@Override
public String method() {
return request.method();
}
@Override
public Map<String, String> headers() {
ArrayMap<String, String> headers = new ArrayMap<>();
if(request.headers() != null){
Set<String> keys = request.headers().names();
if(keys != null){
for(String key : keys){
headers.put(key, request.headers().get(key));
}
}
}
return headers;
}
@Override
public String getHeader(String key) {
if(!TextUtils.isEmpty(key) && request.headers() != null){
return request.headers().get(key);
}else{
return "";
}
}
@Override
public long cacheAge() {
CacheControl cacheControl = request.cacheControl();
if(cacheControl != null){
return cacheControl.maxAgeSeconds() * 1000L;
}
return 0;
}
@Override
public Object tag() {
return request.tag();
}
@Override
public void cancel() {
if(call != null && !call.isCanceled()){
call.cancel();
}
}
public static class Builder extends AbstractBuilder{
Request.Builder builder;
String method = GET;
HttpUrl.Builder urlBuilder;
RequestBody requestBody = null;
public Builder(){
builder = new Request.Builder();
urlBuilder = new HttpUrl.Builder();
}
@Override
public Builder url(String url) {
HttpUrl httpUrl = HttpUrl.parse(url);
if(httpUrl != null){
urlBuilder = httpUrl.newBuilder();
}
return this;
}
@Override
public Builder method(@HttpMethod String method) {
this.method = method;
return this;
}
@Override
public Builder headers(Map<String, String> headers) {
if(headers != null){
Set<String> keys = headers.keySet();
for(String key : keys){
String value = headers.get(key);
if(value != null){
builder.addHeader(key, value);
}
}
}
return this;
}
@Override
public Builder query(String name, String value) {
return query(name, value, true);
}
@Override
public Builder query(String name, String value, boolean encoded) {
if(encoded){
urlBuilder.addEncodedQueryParameter(name, value);
}else{
urlBuilder.addQueryParameter(name, value);
}
return this;
}
@Override
public Builder path(String path) {
return path(path, false);
}
@Override
public Builder path(String path, boolean encoded) {
if(encoded){
urlBuilder.addEncodedPathSegment(path);
}else{
urlBuilder.addPathSegment(path);
}
return this;
}
@Override
public Builder addHeader(String key, String value) {
if(!TextUtils.isEmpty(key) && value != null){
builder.addHeader(key, value);
}
return this;
}
@Override
public Builder cacheAge(long cacheAge) {
if (cacheAge > 0) {
CacheControl cacheControl = new CacheControl.Builder()
.maxAge((int)cacheAge, TimeUnit.MILLISECONDS)
.build();
builder.cacheControl(cacheControl);
}
return this;
}
@Override
public Builder requestBody(HttpRequestBody body) {
if(body == null){
return this;
}
switch (body.getType()){
case HttpRequestBody.TYPE_JSON:
String realBody = body.getContents().get("com.samsung.android.app.sreminder.json");
if(!TextUtils.isEmpty(realBody)){
MediaType JSON = MediaType.parse("application/json; charset="
+ (TextUtils.isEmpty(body.getCharset()) ? "utf-8" : body.getCharset()));
requestBody = RequestBody.create(JSON, realBody);
}
break;
case HttpRequestBody.TYPE_FORM:
requestBody = RequestBodyUtils.getFormBody(body.getContents());
break;
default:break;
}
return this;
}
@Override
public Builder removeHeader(String key) {
if(!TextUtils.isEmpty(key)){
builder.removeHeader(key);
}
return this;
}
@Override
public Builder tag(Object tag) {
builder.tag(tag);
return this;
}
@Override
public HttpRequest build() {
if(requestBody != null){
switch (method){
case GET:
case POST:
builder.post(requestBody);
break;
case DEL:
builder.delete(requestBody);
break;
case PUT:
builder.put(requestBody);
break;
default:
builder.post(requestBody);
break;
}
}else{
switch (method){
case DEL:
builder.delete();
break;
default:
builder.get();
break;
}
}
return new HttpRequest(builder.url(urlBuilder.build()).build());
}
}
}
三、网络请求实体类
public class HttpRequestBody {
public static final int TYPE_JSON = 1;
public static final int TYPE_FORM = 2;
int type;
String charset;
Map<String, String> contents;
private HttpRequestBody(int type, String charset){
contents = new ArrayMap<>();
this.type = type;
this.charset = charset;
}
public static HttpRequestBody json(String json, String charset){
HttpRequestBody requestBody = new HttpRequestBody(TYPE_JSON, charset);
requestBody.add("com.samsung.android.app.sreminder.json", json);
return requestBody;
}
public static HttpRequestBody json(Object obj, String charset){
HttpRequestBody requestBody = new HttpRequestBody(TYPE_JSON, charset);
if(obj != null){
requestBody.add("com.samsung.android.app.sreminder.json", new Gson().toJson(obj));
}
return requestBody;
}
public static HttpRequestBody form(){
return new HttpRequestBody(TYPE_FORM, null);
}
public void add(String key, String val){
contents.put(key, val);
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getCharset() {
return charset;
}
public void setCharset(String charset) {
this.charset = charset;
}
public Map<String, String> getContents() {
return contents;
}
public void setContents(Map<String, String> contents) {
this.contents = contents;
}
}
四、网络请求实体工具类
public class RequestBodyUtils {
public static RequestBody getFormBody(Map<String, String> params){
FormBody.Builder builder = new FormBody.Builder();
if(params != null){
Set<String> keys = params.keySet();
for(String key : keys){
builder.add(key, params.get(key));
}
}
return builder.build();
}
}
五、网络响应头信息类
public class ResponseInfo {
//response's headers
private int statusCode;
private boolean isCache;
private Map<String, List<String>> headers;
private HttpRequest httpRequest;
ResponseInfo(HttpRequest httpRequest){
this.httpRequest = httpRequest;
}
void setStatusCode(int code) {
this.statusCode = code;
}
void setCache(boolean isCache){
this.isCache = isCache;
}
void setHeaders(Map<String, List<String>> headers){
this.headers = headers;
}
public @Nullable HttpRequest getHttpRequest(){
return httpRequest;
}
public int getStatusCode() {
return statusCode;
}
public boolean isCache() {
return isCache;
}
public Map<String, List<String>> getHeaders(){
return headers;
}
}
六、网络响应总信息类
public class HttpResponse<T> {
private T body;
private ResponseInfo responseInfo;
void setBody(T body) {
this.body = body;
}
void setResponseInfo(ResponseInfo responseInfo) {
this.responseInfo = responseInfo;
}
public ResponseInfo getResponseInfo() {
return responseInfo;
}
public T getBody() {
return body;
}
}
七、SSLSocketFactory类
public class SSLSocketFactoryCompat extends SSLSocketFactory {
private SSLSocketFactory defaultFactory;
// Android 5.0+ (API level21) provides reasonable default settings
// but it still allows SSLv3
// https://developer.android.com/about/versions/android-5.0-changes.html#ssl
static String protocols[] = null, cipherSuites[] = null;
static {
try {
SSLSocket socket = (SSLSocket)SSLSocketFactory.getDefault().createSocket();
if (socket != null) {
/* set reasonable protocol versions */
// - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0)
// - remove all SSL versions (especially SSLv3) because they're insecure now
List<String> protocols = new LinkedList<>();
for (String protocol : socket.getSupportedProtocols())
if (!protocol.toUpperCase().contains("SSL"))
protocols.add(protocol);
SSLSocketFactoryCompat.protocols = protocols.toArray(new String[protocols.size()]);
/* set up reasonable cipher suites */
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// choose known secure cipher suites
List<String> allowedCiphers = Arrays.asList(
// TLS 1.2
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECHDE_RSA_WITH_AES_128_GCM_SHA256",
// maximum interoperability
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA",
// additionally
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
List<String> availableCiphers = Arrays.asList(socket.getSupportedCipherSuites());
// take all allowed ciphers that are available and put them into preferredCiphers
HashSet<String> preferredCiphers = new HashSet<>(allowedCiphers);
preferredCiphers.retainAll(availableCiphers);
/* For maximum security, preferredCiphers should *replace* enabled ciphers (thus disabling
* ciphers which are enabled by default, but have become unsecure), but I guess for
* the security level of DAVdroid and maximum compatibility, disabling of insecure
* ciphers should be a server-side task */
// add preferred ciphers to enabled ciphers
HashSet<String> enabledCiphers = preferredCiphers;
enabledCiphers.addAll(new HashSet<>(Arrays.asList(socket.getEnabledCipherSuites())));
SSLSocketFactoryCompat.cipherSuites = enabledCiphers.toArray(new String[enabledCiphers.size()]);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public SSLSocketFactoryCompat(X509TrustManager tm) {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, (tm != null) ? new X509TrustManager[] { tm } : null, null);
defaultFactory = sslContext.getSocketFactory();
} catch (GeneralSecurityException e) {
throw new AssertionError(); // The system has no TLS. Just give up.
}
}
private void upgradeTLS(SSLSocket ssl) {
// Android 5.0+ (API level21) provides reasonable default settings
// but it still allows SSLv3
// https://developer.android.com/about/versions/android-5.0-changes.html#ssl
if (protocols != null) {
ssl.setEnabledProtocols(protocols);
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && cipherSuites != null) {
ssl.setEnabledCipherSuites(cipherSuites);
}
}
@Override
public String[] getDefaultCipherSuites() {
return cipherSuites;
}
@Override
public String[] getSupportedCipherSuites() {
return cipherSuites;
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
Socket ssl = defaultFactory.createSocket(s, host, port, autoClose);
if (ssl instanceof SSLSocket)
upgradeTLS((SSLSocket)ssl);
return ssl;
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
Socket ssl = defaultFactory.createSocket(host, port);
if (ssl instanceof SSLSocket)
upgradeTLS((SSLSocket)ssl);
return ssl;
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
Socket ssl = defaultFactory.createSocket(host, port, localHost, localPort);
if (ssl instanceof SSLSocket)
upgradeTLS((SSLSocket)ssl);
return ssl;
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
Socket ssl = defaultFactory.createSocket(host, port);
if (ssl instanceof SSLSocket)
upgradeTLS((SSLSocket)ssl);
return ssl;
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
Socket ssl = defaultFactory.createSocket(address, port, localAddress, localPort);
if (ssl instanceof SSLSocket)
upgradeTLS((SSLSocket)ssl);
return ssl;
}
}
八、网络请求管理核心类
public class SAHttpClient {
private static final String TAG = "SAHttpClient";
private static final String CACHE_FILE_NAME = "SA_HTTP_CACHE";
private static final int CACHE_SIZE = 10 * 1024 * 1024; // 10 MiB
OkHttpClient httpClient;
private Cache cache;
private SAHttpClient() {
initOkHttpClient();
}
public <T> T requestSync(@NonNull HttpRequest request, Class<T> clazz) throws IOException {
HttpResponse<T> httpResponse = request(request, clazz);
return httpResponse.getBody();
}
public <T> HttpResponse<T> request(@NonNull HttpRequest request, Class<T> clazz) throws IOException {
Response response = httpClient.newCall(request.request).execute();
HttpResponse<T> httpResponse = new HttpResponse<>();
if (response != null) {
ResponseInfo responseInfo = new ResponseInfo(request);
responseInfo.setStatusCode(response.code());
responseInfo.setCache(response.cacheResponse() != null);
if(response.headers() != null){
responseInfo.setHeaders(response.headers().toMultimap());
}
httpResponse.setResponseInfo(responseInfo);
String url = "";
if(response.request() != null && response.request().url() != null){
url = response.request().url().toString();
}
SAappLog.dTag(TAG, "%1$s's response code: %2$d, message:%3$s",url, response.code(), response.message());
try {
T res;
String resString = response.body().string();
if (clazz != String.class) {
res = new Gson().fromJson(resString, clazz);
} else {
res = (T) resString;
}
httpResponse.setBody(res);
} catch (Exception e) {
e.printStackTrace();
}
}
return httpResponse;
}
public <T> void request(@NonNull final HttpRequest request, final Class<T> clazz, final HttpClientListener<T> httpClientListener){
Call call = httpClient.newCall(request.request);
request.call = call;
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
SAappLog.dTag(TAG, "onFailure :" + e.getMessage());
if(httpClientListener != null){
httpClientListener.onFailure(e, new ResponseInfo(request));
}
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response != null) {
String url = "";
if(response.request() != null && response.request().url() != null){
url = getPrintableUrl(response.request().url());
}
SAappLog.dTag(TAG, "%1$s's response code: %2$d, message:%3$s",url, response.code(), response.message());
if(httpClientListener == null){
return;
}
ResponseInfo responseInfo = new ResponseInfo(request);
responseInfo.setStatusCode(response.code());
responseInfo.setCache(response.cacheResponse() != null);
if(response.headers() != null){
responseInfo.setHeaders(response.headers().toMultimap());
}
if (response.isSuccessful()) {
try {
String resString = response.body().string();
T res;
if (clazz != String.class) {
res = new Gson().fromJson(resString, clazz);
} else {
res = (T) resString;
}
httpClientListener.onResponse(res, responseInfo);
} catch (Exception e) {
e.printStackTrace();
httpClientListener.onFailure(e, responseInfo);
}
} else {
String message = response.message();
response.close();
httpClientListener.onFailure(new IllegalAccessException(message), responseInfo);
}
} else {
if(httpClientListener != null){
httpClientListener.onFailure(new IllegalAccessException("null response"), new ResponseInfo(request));
}
}
}
});
}
/** 根据Tag取消请求 */
public void cancelTag(Object tag) {
if (tag == null) return;
SAappLog.dTag(TAG, "cancel tag:" + tag.toString());
for (Call call : httpClient.dispatcher().queuedCalls()) {
if (tag.equals(call.request().tag())) {
call.cancel();
}
}
for (Call call : httpClient.dispatcher().runningCalls()) {
if (tag.equals(call.request().tag())) {
call.cancel();
}
}
}
/** 取消所有请求请求 */
public void cancelAll() {
SAappLog.dTag(TAG, "cancel all");
if (httpClient == null) return;
for (Call call : httpClient.dispatcher().queuedCalls()) {
call.cancel();
}
for (Call call : httpClient.dispatcher().runningCalls()) {
call.cancel();
}
}
private void initOkHttpClient() {
try {
if (httpClient == null) {
File httpCacheDirectory = new File(SReminderApp.getInstance().getCacheDir(), CACHE_FILE_NAME);
cache = new Cache(httpCacheDirectory, CACHE_SIZE);
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.cache(cache)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.addInterceptor(new ApplicationInterceptor())
.addNetworkInterceptor(new NetworkInterceptor());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
X509TrustManager trustAllCert = new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
};
SSLSocketFactory sslSocketFactory = new SSLSocketFactoryCompat(trustAllCert);
builder.sslSocketFactory(sslSocketFactory, trustAllCert);
}
if (BuildConfig.DEBUG) {
//when DEBUG , show the request body
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(loggingInterceptor);
}else if (Build.TYPE.equalsIgnoreCase("eng")){
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
builder.addInterceptor(loggingInterceptor);
}
httpClient = builder.build();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static final SAHttpClient getInstance() {
return SAHttpClientHolder.INSTANCE;
}
public OkHttpClient getHttpClient() {
initOkHttpClient();
return httpClient;
}
private static class ApplicationInterceptor implements Interceptor {
ApplicationInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
if (chain != null && chain.request() != null) {
if (chain.request().url() != null) {
SAappLog.dTag(TAG, "ApplicationInterceptor.intercept " + getPrintableUrl(chain.request().url()));
}
return chain.proceed(chain.request());
} else {
return new Response.Builder().build();
}
}
}
static String getPrintableUrl(HttpUrl httpUrl){
if(BuildConfig.DEBUG || Build.TYPE.equalsIgnoreCase("eng")){
return httpUrl.toString();
}else{
if (httpUrl.fragment() != null) {
return httpUrl.fragment();
} else if (httpUrl.host() != null) {
return httpUrl.host();
} else {
return "dummy_url";
}
}
}
private static class NetworkInterceptor implements Interceptor {
NetworkInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
if (chain.request().url() != null) {
SAappLog.dTag(TAG, "NetworkInterceptor.intercept " + getPrintableUrl(chain.request().url()));
}
return chain.proceed(chain.request());
}
}
private static class SAHttpClientHolder {
private static final SAHttpClient INSTANCE = new SAHttpClient();
}
public interface HttpClientListener<T> {
void onResponse(T response, ResponseInfo responseInfo);
void onFailure(Exception e, ResponseInfo responseInfo);
}
}
网友评论