package com.example.http;
import android.content.Context;
import com.example.http.utils.CheckNetwork;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.FieldNamingStrategy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Created by jingbin on 2017/2/14.
* 网络请求工具类
* <p>
* 豆瓣api:
* 问题:API限制为每分钟40次,一不小心就超了,马上KEY就被封,用不带KEY的API,每分钟只有可怜的10次。
* 返回:code:112(rate_limit_exceeded2 IP 访问速度限制)
* 解决:1.使用每分钟访问次数限制(客户端)2.更换ip (更换wifi)
* 豆瓣开发者服务使用条款: https://developers.douban.com/wiki/?title=terms
* 使用时请在"CloudReaderApplication"下初始化。
*/
public class HttpUtils {
private static HttpUtils instance;
private Gson gson;
private Context context;
private Object gankHttps;
private Object doubanHttps;
private Object dongtingHttps;
private IpmlTokenGetListener listener;
private boolean debug;
// gankio、豆瓣、(轮播图)
private final static String API_GANKIO = "https://gank.io/api/";
private final static String API_DOUBAN = "Https://api.douban.com/";
private final static String API_TING = "https://tingapi.ting.baidu.com/v1/restserver/";
/**
* 分页数据,每页的数量
*/
public static int per_page = 10;
public static int per_page_more = 20;
public static HttpUtils getInstance() {
if (instance == null) {
synchronized (HttpUtils.class) {
if (instance == null) {
instance = new HttpUtils();
}
}
}
return instance;
}
public void init(Context context, boolean debug) {
this.context = context;
this.debug = debug;
HttpHead.init(context);
}
public <T> T getGankIOServer(Class<T> a) {
if (gankHttps == null) {
synchronized (HttpUtils.class) {
if (gankHttps == null) {
gankHttps = getBuilder(API_GANKIO).build().create(a);
}
}
}
return (T) gankHttps;
}
public <T> T getDouBanServer(Class<T> a) {
if (doubanHttps == null) {
synchronized (HttpUtils.class) {
if (doubanHttps == null) {
doubanHttps = getBuilder(API_DOUBAN).build().create(a);
}
}
}
return (T) doubanHttps;
}
public <T> T getTingServer(Class<T> a) {
if (dongtingHttps == null) {
synchronized (HttpUtils.class) {
if (dongtingHttps == null) {
dongtingHttps = getBuilder(API_TING).build().create(a);
}
}
}
return (T) dongtingHttps;
}
private Retrofit.Builder getBuilder(String apiUrl) {
Retrofit.Builder builder = new Retrofit.Builder();
builder.client(getOkClient());
builder.baseUrl(apiUrl);//设置远程地址
builder.addConverterFactory(new NullOnEmptyConverterFactory());
builder.addConverterFactory(GsonConverterFactory.create(getGson()));
builder.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
return builder;
}
private Gson getGson() {
if (gson == null) {
GsonBuilder builder = new GsonBuilder();
builder.setLenient();
builder.setFieldNamingStrategy(new AnnotateNaming());
builder.serializeNulls();
gson = builder.create();
}
return gson;
}
private static class AnnotateNaming implements FieldNamingStrategy {
@Override
public String translateName(Field field) {
ParamNames a = field.getAnnotation(ParamNames.class);
return a != null ? a.value() : FieldNamingPolicy.IDENTITY.translateName(field);
}
}
public OkHttpClient getUnsafeOkHttpClient() {
try {
final TrustManager[] trustAllCerts = 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[]{};
}
}};
// Install the all-trusting trust manager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new SecureRandom());
// Create an ssl socket factory with our all-trusting manager
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder okBuilder = new OkHttpClient.Builder();
okBuilder.readTimeout(20, TimeUnit.SECONDS);
okBuilder.connectTimeout(10, TimeUnit.SECONDS);
okBuilder.writeTimeout(20, TimeUnit.SECONDS);
okBuilder.addInterceptor(new HttpHeadInterceptor());
okBuilder.addInterceptor(getInterceptor());
okBuilder.sslSocketFactory(sslSocketFactory);
okBuilder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
// Log.d("HttpUtils", "==come");
return true;
}
});
return okBuilder.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public OkHttpClient getOkClient() {
OkHttpClient client1;
client1 = getUnsafeOkHttpClient();
return client1;
}
public void setTokenListener(IpmlTokenGetListener listener) {
this.listener = listener;
}
class HttpHeadInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder builder = request.newBuilder();
builder.addHeader("Accept", "application/json;versions=1");
if (CheckNetwork.isNetworkConnected(context)) {
int maxAge = 60;
builder.addHeader("Cache-Control", "public, max-age=" + maxAge);
} else {
int maxStale = 60 * 60 * 24 * 28;
builder.addHeader("Cache-Control", "public, only-if-cached, max-stale=" + maxStale);
}
// 可添加token
// if (listener != null) {
// builder.addHeader("token", listener.getToken());
// }
// 如有需要,添加请求头
// builder.addHeader("a", HttpHead.getHeader(request.method()));
return chain.proceed(builder.build());
}
}
private HttpLoggingInterceptor getInterceptor() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
if (debug) {
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); // 测试
} else {
interceptor.setLevel(HttpLoggingInterceptor.Level.NONE); // 打包
}
return interceptor;
}
}