httpdns 缓存策略,特殊接口获取 httpdns 服务

This commit is contained in:
wangcongtao
2020-11-20 09:53:08 +08:00
parent 65a380cd42
commit 5fa8644bb3
15 changed files with 392 additions and 53 deletions

View File

@@ -5,16 +5,19 @@ import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.alibaba.android.arouter.launcher.ARouter;
import com.mogo.commons.network.SubscribeImpl;
import com.mogo.httpdns.IHttpDnsCallback;
import com.mogo.httpdns.IMogoHttpDns;
import com.mogo.httpdns.MogoHttpDnsHandler;
import com.mogo.module.common.MogoApisHandler;
import com.mogo.utils.UiThreadHandler;
import com.mogo.utils.WorkThreadHandler;
import com.mogo.utils.network.RequestOptions;
import java.util.Collection;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@@ -24,6 +27,7 @@ public class MainActivity extends AppCompatActivity {
private IMogoHttpDns httpDns;
private View send;
private View fresh;
private TextView content;
@Override
@@ -32,9 +36,10 @@ public class MainActivity extends AppCompatActivity {
setContentView( R.layout.activity_main );
send = findViewById( R.id.send );
fresh = findViewById( R.id.fresh );
content = findViewById( R.id.content );
httpDns = ARouter.getInstance().navigation( IMogoHttpDns.class );
httpDns = MogoHttpDnsHandler.getHttpDnsApi();
apiServices = MogoApisHandler.getInstance().getApis().getNetworkApi().create( ApiServices.class, "https://dnstest.zhidaozhixing.com" );
send.setOnClickListener( new View.OnClickListener() {
@@ -62,16 +67,36 @@ public class MainActivity extends AppCompatActivity {
} );
}
} );
fresh.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick( View v ) {
WorkThreadHandler.getInstance().post( new Runnable() {
@Override
public void run() {
httpDns.getHttpDnsIp( "dnstest.zhidaozhixing.com", false, new IHttpDnsCallback() {
@Override
public void onParsed( @Nullable String ip ) {
StringBuilder sb = new StringBuilder( "httpDns ip:\n" );
sb.append( ip ).append( "\n" );
UiThreadHandler.post( new Runnable() {
@Override
public void run() {
content.setText( sb.toString() );
}
} );
}
} );
}
} );
}
} );
}
private void renderResponse( ResponseBody body ) {
StringBuilder sb = new StringBuilder( "httpDns ip:\n" );
Collection< String > ips = httpDns.getHttpDnsIps( "dnstest.zhidaozhixing.com" );
if ( ips != null && !ips.isEmpty() ) {
for ( String ip : ips ) {
sb.append( ip ).append( "\n" );
}
}
String ip = httpDns.getCachedHttpDnsIps( "dnstest.zhidaozhixing.com" );
sb.append( ip ).append( "\n" );
sb.append( "\nserverIp: \n" ).append( body.result.serverIp ).append( "\n" );
content.setText( sb.toString() );
}

View File

@@ -6,12 +6,24 @@
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="发起请求" />
android:padding="20dp">
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发起接口请求" />
<Button
android:id="@+id/fresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发起dns请求" />
</LinearLayout>
<ScrollView
android:layout_width="match_parent"

View File

@@ -22,7 +22,7 @@ android {
buildTypes {
release {
minifyEnabled false
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

View File

@@ -1,5 +1,7 @@
package com.mogo.httpdns;
import androidx.annotation.Keep;
public
/**
* @author congtaowang
@@ -7,7 +9,9 @@ public
*
* 描述
*/
@Keep
class HttpDnsConst {
@Keep
public static final String PATH = "/httpdns/api";
}

View File

@@ -0,0 +1,18 @@
package com.mogo.httpdns;
import androidx.annotation.Keep;
import androidx.annotation.Nullable;
public
/**
* @author congtaowang
* @since 2020/11/19
*
* dns 解析回调
*/
@Keep
interface IHttpDnsCallback {
@Keep
void onParsed( @Nullable String ip );
}

View File

@@ -0,0 +1,17 @@
package com.mogo.httpdns;
import androidx.annotation.Keep;
public
/**
* @author congtaowang
* @since 2020/11/19
*
* dns ttl 通知
*/
@Keep
interface IHttpDnsTtlCallback {
@Keep
void onTtl();
}

View File

@@ -1,5 +1,8 @@
package com.mogo.httpdns;
import androidx.annotation.Keep;
import androidx.annotation.Nullable;
import com.alibaba.android.arouter.facade.template.IProvider;
import com.mogo.utils.network.HttpDns;
@@ -13,9 +16,47 @@ public
*
* http 请求做http dns转换
*/
@Keep
interface IMogoHttpDns extends IProvider {
/**
* 获取 dns 代理实例
*
* @return
*/
@Nullable
HttpDns dns();
Collection< String > getHttpDnsIps( String host );
/**
* 获取缓存中的 dns ip地址
*
* @param host
* @return
*/
@Nullable
String getCachedHttpDnsIps( String host );
/**
* dns 解析
*
* @param host 域名
* @param useCache 是否使用缓存,是 - 如果没有缓存,则解析新地址、否 - 解析新地址,并将新地址缓存
* @param callback
*/
void getHttpDnsIp( String host, boolean useCache, IHttpDnsCallback callback );
/**
* 监听 ttl 回调
*
* @param host 域名
* @param callback
*/
void addHttpDnsTtlCallback( String host, IHttpDnsTtlCallback callback );
/**
* 注销 ttl 回调
*
* @param host 域名
*/
void removeHttpDnsTtlCallback( String host );
}

View File

@@ -0,0 +1,29 @@
package com.mogo.httpdns;
import androidx.annotation.Keep;
import com.alibaba.android.arouter.launcher.ARouter;
public
/**
* @author congtaowang
* @since 2020/11/19
*
* 描述
*/
@Keep
class MogoHttpDnsHandler {
private static IMogoHttpDns sHttpDns;
public static IMogoHttpDns getHttpDnsApi() {
if ( sHttpDns == null ) {
synchronized ( MogoHttpDnsHandler.class ) {
if ( sHttpDns == null ) {
sHttpDns = ARouter.getInstance().navigation( IMogoHttpDns.class );
}
}
}
return sHttpDns;
}
}

View File

@@ -4,12 +4,11 @@ import android.content.Context;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.mogo.httpdns.HttpDnsConst;
import com.mogo.httpdns.IHttpDnsCallback;
import com.mogo.httpdns.IHttpDnsTtlCallback;
import com.mogo.httpdns.IMogoHttpDns;
import com.mogo.utils.network.HttpDns;
import java.util.Collection;
import java.util.List;
public
/**
* @author congtaowang
@@ -26,10 +25,25 @@ class HttpDnsNoop implements IMogoHttpDns {
}
@Override
public Collection< String > getHttpDnsIps( String host ) {
public String getCachedHttpDnsIps( String host ) {
return null;
}
@Override
public void getHttpDnsIp( String host, boolean useCache, IHttpDnsCallback callback ) {
}
@Override
public void addHttpDnsTtlCallback( String host, IHttpDnsTtlCallback callback ) {
}
@Override
public void removeHttpDnsTtlCallback( String host ) {
}
@Override
public void init( Context context ) {

View File

@@ -1,10 +1,19 @@
package com.mogo.httpdns.tencent;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import com.mogo.httpdns.IHttpDnsTtlCallback;
import com.mogo.utils.ThreadPoolService;
import com.mogo.utils.logger.Logger;
import com.tencent.msdk.dns.MSDKDnsResolver;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author congtaowang
@@ -14,19 +23,149 @@ import java.util.Set;
*/
class HttpDnsIpsCache {
private static final String TAG = "HttpDnsIpsCache";
// 缓存过期时间
public static final long INTERVAL_CACHE = 10 * 60 * 1000;
public static final long INTERVAL_CACHE = 1 * 60 * 1000;
public static Map< String, Set< String > > sCaches = new HashMap<>();
// 刷新缓存时间
public static final long TTL = ( long ) ( INTERVAL_CACHE * 0.75 );
static void cache( String host, String ip ) {
if ( !sCaches.containsKey( host ) ) {
sCaches.put( host, new HashSet< String >() );
// 使用dns新域名
public static final int MSG_DNS_FLUSH = 6000000;
// ttl
public static final int MSG_DNS_TTL = 6000001;
private static Map< String, String > sCaches = new ConcurrentHashMap<>();
private static Map< String, String > sTTLCaches = new ConcurrentHashMap<>();
private static Map< String, IHttpDnsTtlCallback > sTtlCallbacks = new ConcurrentHashMap<>();
private static Handler sHandler = new Handler( Looper.getMainLooper() ) {
@Override
public void handleMessage( Message msg ) {
super.handleMessage( msg );
if ( msg.what == MSG_DNS_FLUSH ) {
flushNewDnsCache();
postTtlCallback();
loopDnsParse();
} else if ( msg.what == MSG_DNS_TTL ) {
parseHosts();
}
}
};
/**
* 将 ttl 消息回调
*/
static void postTtlCallback() {
if ( sTtlCallbacks.isEmpty() ) {
return;
}
Collection< IHttpDnsTtlCallback > callbacks = sTtlCallbacks.values();
if ( callbacks == null || callbacks.isEmpty() ) {
return;
}
for ( IHttpDnsTtlCallback callback : callbacks ) {
if ( callback == null ) {
continue;
}
try {
callback.onTtl();
} catch ( Exception e ) {
e.printStackTrace();
}
}
sCaches.get( host ).add( ip );
}
static Collection< String > getHttpDnsIps( String host ) {
/**
* 缓存域名
*
* @param host
* @param ip
*/
static void cache( String host, String ip ) {
sCaches.put( host, ip );
}
/**
* 获取缓存中的域名
*
* @param host
* @return
*/
static String getHttpDnsIps( String host ) {
return sCaches.get( host );
}
/**
* 使用新的 dns 缓存
*/
static void flushNewDnsCache() {
sCaches.clear();
sCaches.putAll( sTTLCaches );
}
/**
* ttl 到达后,刷新一遍 dns 域名
*/
static void loopDnsParse() {
Logger.d( TAG, "使用新的dns列表" );
sHandler.sendEmptyMessageDelayed( MSG_DNS_FLUSH, INTERVAL_CACHE );
sHandler.sendEmptyMessageDelayed( MSG_DNS_TTL, TTL );
}
/**
* ttl 到期,刷新域名
*/
static void parseHosts() {
Logger.d( TAG, "ttl 过期刷新dns列表" );
ThreadPoolService.execute( new Runnable() {
@Override
public void run() {
Set< String > hostSet = sCaches.keySet();
if ( hostSet.isEmpty() ) {
return;
}
for ( String host : hostSet ) {
String newIp = parseHostFromHttpDns( host );
if ( TextUtils.isEmpty( newIp ) ) {
continue;
}
sTTLCaches.put( host, newIp );
}
}
} );
}
/**
* 使用腾讯服务解析域名
*
* @param host
* @return
*/
static String parseHostFromHttpDns( String host ) {
String ips = MSDKDnsResolver.getInstance().getAddrByName( host );
String[] ipArr = ips.split( ";" );
if ( 0 == ipArr.length ) {
return null;
}
for ( String ip : ipArr ) {
if ( TextUtils.isEmpty( ip ) || TextUtils.equals( "0", ip ) ) {
continue;
}
Logger.d( TAG, "parse: %s - %s", host, ip );
return ip;
}
return null;
}
static void addHttpDnsTtlCallback( String host, IHttpDnsTtlCallback callback ) {
sTtlCallbacks.put( host, callback );
}
static void removeHttpDnsTtlCallback( String host ) {
sTtlCallbacks.remove( host );
}
}

View File

@@ -1,10 +1,13 @@
package com.mogo.httpdns.tencent;
import android.content.Context;
import android.text.TextUtils;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.mogo.commons.debug.DebugConfig;
import com.mogo.httpdns.HttpDnsConst;
import com.mogo.httpdns.IHttpDnsCallback;
import com.mogo.httpdns.IHttpDnsTtlCallback;
import com.mogo.httpdns.IMogoHttpDns;
import com.mogo.utils.logger.Logger;
import com.mogo.utils.network.HttpDns;
@@ -12,8 +15,7 @@ import com.tencent.msdk.dns.MSDKDnsResolver;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -38,33 +40,63 @@ class TencentHttpDns implements IMogoHttpDns, HttpDns {
@Override
public List< InetAddress > lookup( String hostname ) throws UnknownHostException {
String ips = MSDKDnsResolver.getInstance().getAddrByName( hostname );
Logger.d( TAG, hostname + " ips: %s", ips );
String[] ipArr = ips.split( ";" );
if ( 0 == ipArr.length ) {
Logger.d( TAG, "需要dns解析" );
String cacheIp = getCacheOrParseIpIfNecessary( hostname );
if ( TextUtils.isEmpty( cacheIp ) ) {
return Collections.emptyList();
}
List< InetAddress > inetAddressList = new ArrayList<>( ipArr.length );
for ( String ip : ipArr ) {
if ( "0".equals( ip ) ) {
continue;
}
HttpDnsIpsCache.cache( hostname, ip );
try {
InetAddress inetAddress = InetAddress.getByName( ip );
inetAddressList.add( inetAddress );
} catch ( UnknownHostException ignored ) {
Logger.e( TAG, ignored, "lookup invoked." );
}
}
return inetAddressList;
return Arrays.asList( InetAddress.getAllByName( cacheIp ) );
}
@Override
public Collection< String > getHttpDnsIps( String host ) {
public String getCachedHttpDnsIps( String host ) {
return HttpDnsIpsCache.getHttpDnsIps( host );
}
private String getCacheOrParseIpIfNecessary( String host ) {
String cacheIp = HttpDnsIpsCache.getHttpDnsIps( host );
if ( TextUtils.isEmpty( cacheIp ) ) {
cacheIp = HttpDnsIpsCache.parseHostFromHttpDns( host );
if ( !TextUtils.isEmpty( cacheIp ) ) {
HttpDnsIpsCache.cache( host, cacheIp );
}
}
return cacheIp;
}
@Override
public void getHttpDnsIp( String host, boolean useCache, IHttpDnsCallback callback ) {
String cacheIp = null;
if ( useCache ) {
cacheIp = getCacheOrParseIpIfNecessary( host );
} else {
cacheIp = HttpDnsIpsCache.parseHostFromHttpDns( host );
if ( !TextUtils.isEmpty( cacheIp ) ) {
HttpDnsIpsCache.cache( host, cacheIp );
}
}
if ( !TextUtils.isEmpty( cacheIp ) ) {
if ( callback != null ) {
callback.onParsed( cacheIp );
return;
}
}
if ( callback != null ) {
callback.onParsed( null );
}
}
@Override
public void addHttpDnsTtlCallback( String host, IHttpDnsTtlCallback callback ) {
HttpDnsIpsCache.addHttpDnsTtlCallback( host, callback );
}
@Override
public void removeHttpDnsTtlCallback( String host ) {
HttpDnsIpsCache.removeHttpDnsTtlCallback( host );
}
@Override
public void init( Context context ) {
if ( sInited ) {
@@ -77,6 +109,8 @@ class TencentHttpDns implements IMogoHttpDns, HttpDns {
DebugConfig.isDebug(),
1_000
);
MSDKDnsResolver.getInstance().WGSetDnsOpenId( "1AE58PG9444E3G9L" );
HttpDnsIpsCache.loopDnsParse();
sInited = true;
}
}

View File

@@ -19,6 +19,7 @@ import com.mogo.commons.network.ParamsUtil;
import com.mogo.commons.network.X509TrustManagerImpl;
import com.mogo.commons.storage.SpStorage;
import com.mogo.httpdns.IMogoHttpDns;
import com.mogo.httpdns.MogoHttpDnsHandler;
import com.mogo.utils.ThreadPoolService;
import com.mogo.utils.TipToast;
import com.mogo.utils.network.NetConfig;
@@ -146,7 +147,7 @@ public abstract class AbsMogoApplication extends Application {
} catch ( Exception e ) {
}
IMogoHttpDns dns = ARouter.getInstance().navigation( IMogoHttpDns.class );
IMogoHttpDns dns = MogoHttpDnsHandler.getHttpDnsApi();
NetConfig.instance().setSignaturePrefix( Constants.SIGN_PREFIX )
.setPublicParams( ParamsUtil.getStaticParams() )

View File

@@ -1,11 +1,11 @@
package com.mogo.utils.network;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import okhttp3.ConnectionPool;
import okhttp3.Dns;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
@@ -52,7 +52,11 @@ public final class OkHttpFactory {
HttpDns httpDns = NetConfig.instance().getHttpDns();
if ( httpDns != null ) {
builder.dns( hostname -> {
return httpDns.lookup( hostname );
List< InetAddress > addresses = httpDns.lookup( hostname );
if ( addresses != null && !addresses.isEmpty() ) {
return addresses;
}
return Dns.SYSTEM.lookup( hostname );
} );
}

View File

@@ -12,6 +12,7 @@
android:screenOrientation="landscape"
android:stateNotNeeded="true"
android:taskAffinity=""
android:hardwareAccelerated="true"
android:theme="@style/Main"
android:windowSoftInputMode="adjustPan|stateHidden">
<intent-filter>