HTTPS(含SNI)业务场景“IP直连”方案说明一文介绍了利用HttpDns解析获得ip后进行ip直连的通用方法。但是如果您在Android端使用的网络框架是OkHttp,通过调用OkHttp提供的自定义Dns服务接口,可以更为优雅地使用HttpDns的服务。
OkHttp是一个处理网络请求的开源项目,是Android端最火热的轻量级框架,由移动支付Square公司贡献用于替代HttpUrlConnection和Apache HttpClient。随着OkHttp的不断成熟,越来越多的Android开发者使用OkHttp作为网络框架。
OkHttp默认使用系统DNS服务InetAddress进行域名解析,但同时也暴露了自定义DNS服务的接口,通过该接口我们可以优雅地使用HttpDns。
1. 自定义DNS接口
OkHttp暴露了一个Dns接口,通过实现该接口,我们可以自定义Dns服务:
- [backcolor=transparent]public[backcolor=transparent] [backcolor=transparent]class[backcolor=transparent] [backcolor=transparent]OkHttpDns[backcolor=transparent] [backcolor=transparent]implements[backcolor=transparent] [backcolor=transparent]Dns[backcolor=transparent] [backcolor=transparent]{
- [backcolor=transparent] [backcolor=transparent]private[backcolor=transparent] [backcolor=transparent]static[backcolor=transparent] [backcolor=transparent]final[backcolor=transparent] [backcolor=transparent]Dns[backcolor=transparent] SYSTEM [backcolor=transparent]=[backcolor=transparent] [backcolor=transparent]Dns[backcolor=transparent].[backcolor=transparent]SYSTEM[backcolor=transparent];
- [backcolor=transparent] [backcolor=transparent]HttpDnsService[backcolor=transparent] httpdns[backcolor=transparent];[backcolor=transparent]//httpdns 解析服务
- [backcolor=transparent] [backcolor=transparent]private[backcolor=transparent] [backcolor=transparent]static[backcolor=transparent] [backcolor=transparent]OkHttpDns[backcolor=transparent] instance [backcolor=transparent]=[backcolor=transparent] [backcolor=transparent]null[backcolor=transparent];
- [backcolor=transparent] [backcolor=transparent]private[backcolor=transparent] [backcolor=transparent]OkHttpDns[backcolor=transparent]([backcolor=transparent]Context[backcolor=transparent] context[backcolor=transparent])[backcolor=transparent] [backcolor=transparent]{
- [backcolor=transparent] [backcolor=transparent]this[backcolor=transparent].[backcolor=transparent]httpdns [backcolor=transparent]=[backcolor=transparent] [backcolor=transparent]HttpDns[backcolor=transparent].[backcolor=transparent]getService[backcolor=transparent]([backcolor=transparent]context[backcolor=transparent],[backcolor=transparent] [backcolor=transparent]"account id"[backcolor=transparent]);
- [backcolor=transparent] [backcolor=transparent]}
- [backcolor=transparent] [backcolor=transparent]public[backcolor=transparent] [backcolor=transparent]static[backcolor=transparent] [backcolor=transparent]OkHttpDns[backcolor=transparent] getInstance[backcolor=transparent]([backcolor=transparent]Context[backcolor=transparent] context[backcolor=transparent])[backcolor=transparent] [backcolor=transparent]{
- [backcolor=transparent] [backcolor=transparent]if[backcolor=transparent]([backcolor=transparent]instance [backcolor=transparent]==[backcolor=transparent] [backcolor=transparent]null[backcolor=transparent])[backcolor=transparent] [backcolor=transparent]{
- [backcolor=transparent] instance [backcolor=transparent]=[backcolor=transparent] [backcolor=transparent]new[backcolor=transparent] [backcolor=transparent]OkHttpDns[backcolor=transparent]([backcolor=transparent]context[backcolor=transparent]);
- [backcolor=transparent] [backcolor=transparent]}
- [backcolor=transparent] [backcolor=transparent]return[backcolor=transparent] instance[backcolor=transparent];
- [backcolor=transparent] [backcolor=transparent]}
- [backcolor=transparent] [backcolor=transparent]@Override
- [backcolor=transparent] [backcolor=transparent]public[backcolor=transparent] [backcolor=transparent]List[backcolor=transparent]<[backcolor=transparent]InetAddress[backcolor=transparent]>[backcolor=transparent] lookup[backcolor=transparent]([backcolor=transparent]String[backcolor=transparent] hostname[backcolor=transparent])[backcolor=transparent] [backcolor=transparent]throws[backcolor=transparent] [backcolor=transparent]UnknownHostException[backcolor=transparent] [backcolor=transparent]{
- [backcolor=transparent] [backcolor=transparent]//通过异步解析接口获取ip
- [backcolor=transparent] [backcolor=transparent]String[backcolor=transparent] ip [backcolor=transparent]=[backcolor=transparent] httpdns[backcolor=transparent].[backcolor=transparent]getIpByHostAsync[backcolor=transparent]([backcolor=transparent]hostname[backcolor=transparent]);
- [backcolor=transparent] [backcolor=transparent]if[backcolor=transparent]([backcolor=transparent]ip [backcolor=transparent]!=[backcolor=transparent] [backcolor=transparent]null[backcolor=transparent])[backcolor=transparent] [backcolor=transparent]{
- [backcolor=transparent] [backcolor=transparent]//如果ip不为null,直接使用该ip进行网络请求
- [backcolor=transparent] [backcolor=transparent]List[backcolor=transparent]<[backcolor=transparent]InetAddress[backcolor=transparent]>[backcolor=transparent] inetAddresses [backcolor=transparent]=[backcolor=transparent] [backcolor=transparent]Arrays[backcolor=transparent].[backcolor=transparent]asList[backcolor=transparent]([backcolor=transparent]InetAddress[backcolor=transparent].[backcolor=transparent]getAllByName[backcolor=transparent]([backcolor=transparent]ip[backcolor=transparent]));
- [backcolor=transparent] [backcolor=transparent]Log[backcolor=transparent].[backcolor=transparent]e[backcolor=transparent]([backcolor=transparent]"OkHttpDns"[backcolor=transparent],[backcolor=transparent] [backcolor=transparent]"inetAddresses:"[backcolor=transparent] [backcolor=transparent]+[backcolor=transparent] inetAddresses[backcolor=transparent]);
- [backcolor=transparent] [backcolor=transparent]return[backcolor=transparent] inetAddresses[backcolor=transparent];
- [backcolor=transparent] [backcolor=transparent]}
- [backcolor=transparent] [backcolor=transparent]//如果返回null,走系统DNS服务解析域名
- [backcolor=transparent] [backcolor=transparent]return[backcolor=transparent] [backcolor=transparent]Dns[backcolor=transparent].[backcolor=transparent]SYSTEM[backcolor=transparent].[backcolor=transparent]lookup[backcolor=transparent]([backcolor=transparent]hostname[backcolor=transparent]);
- [backcolor=transparent] [backcolor=transparent]}
- [backcolor=transparent]}
2. 创建OkHttpClient
创建OkHttpClient对象,传入OkHttpDns对象代替默认Dns服务:
- [backcolor=transparent]private[backcolor=transparent] [backcolor=transparent]void[backcolor=transparent] okhttpDnsRequest[backcolor=transparent]()[backcolor=transparent] [backcolor=transparent]{
- [backcolor=transparent] [backcolor=transparent]OkHttpClient[backcolor=transparent] client [backcolor=transparent]=[backcolor=transparent] [backcolor=transparent]new[backcolor=transparent] [backcolor=transparent]OkHttpClient[backcolor=transparent].[backcolor=transparent]Builder[backcolor=transparent]()
- [backcolor=transparent] [backcolor=transparent].[backcolor=transparent]dns[backcolor=transparent]([backcolor=transparent]OkHttpDns[backcolor=transparent].[backcolor=transparent]getInstance[backcolor=transparent]([backcolor=transparent]getApplicationContext[backcolor=transparent]()))
- [backcolor=transparent] [backcolor=transparent].[backcolor=transparent]build[backcolor=transparent]();
- [backcolor=transparent] [backcolor=transparent]Request[backcolor=transparent] request [backcolor=transparent]=[backcolor=transparent] [backcolor=transparent]new[backcolor=transparent] [backcolor=transparent]Request[backcolor=transparent].[backcolor=transparent]Builder[backcolor=transparent]()
- [backcolor=transparent] [backcolor=transparent].[backcolor=transparent]url[backcolor=transparent]([backcolor=transparent]"http://www.aliyun.com"[backcolor=transparent])
- [backcolor=transparent] [backcolor=transparent].[backcolor=transparent]build[backcolor=transparent]();
- [backcolor=transparent] [backcolor=transparent]Response[backcolor=transparent] response [backcolor=transparent]=[backcolor=transparent] [backcolor=transparent]null[backcolor=transparent];
- [backcolor=transparent] client[backcolor=transparent].[backcolor=transparent]newCall[backcolor=transparent]([backcolor=transparent]request[backcolor=transparent]).[backcolor=transparent]enqueue[backcolor=transparent]([backcolor=transparent]new[backcolor=transparent] [backcolor=transparent]Callback[backcolor=transparent]()[backcolor=transparent] [backcolor=transparent]{
- [backcolor=transparent] [backcolor=transparent]@Override
- [backcolor=transparent] [backcolor=transparent]public[backcolor=transparent] [backcolor=transparent]void[backcolor=transparent] onFailure[backcolor=transparent]([backcolor=transparent]Call[backcolor=transparent] call[backcolor=transparent],[backcolor=transparent] [backcolor=transparent]IOException[backcolor=transparent] e[backcolor=transparent])[backcolor=transparent] [backcolor=transparent]{
- [backcolor=transparent] e[backcolor=transparent].[backcolor=transparent]printStackTrace[backcolor=transparent]();
- [backcolor=transparent] [backcolor=transparent]}
- [backcolor=transparent] [backcolor=transparent]@Override
- [backcolor=transparent] [backcolor=transparent]public[backcolor=transparent] [backcolor=transparent]void[backcolor=transparent] onResponse[backcolor=transparent]([backcolor=transparent]Call[backcolor=transparent] call[backcolor=transparent],[backcolor=transparent] [backcolor=transparent]Response[backcolor=transparent] response[backcolor=transparent])[backcolor=transparent] [backcolor=transparent]throws[backcolor=transparent] [backcolor=transparent]IOException[backcolor=transparent] [backcolor=transparent]{
- [backcolor=transparent] [backcolor=transparent]if[backcolor=transparent] [backcolor=transparent](![backcolor=transparent]response[backcolor=transparent].[backcolor=transparent]isSuccessful[backcolor=transparent]())[backcolor=transparent] [backcolor=transparent]throw[backcolor=transparent] [backcolor=transparent]new[backcolor=transparent] [backcolor=transparent]IOException[backcolor=transparent]([backcolor=transparent]"Unexpected code "[backcolor=transparent] [backcolor=transparent]+[backcolor=transparent] response[backcolor=transparent]);
- [backcolor=transparent] [backcolor=transparent]DataInputStream[backcolor=transparent] dis [backcolor=transparent]=[backcolor=transparent] [backcolor=transparent]new[backcolor=transparent] [backcolor=transparent]DataInputStream[backcolor=transparent]([backcolor=transparent]response[backcolor=transparent].[backcolor=transparent]body[backcolor=transparent]().[backcolor=transparent]byteStream[backcolor=transparent]());
- [backcolor=transparent] [backcolor=transparent]int[backcolor=transparent] len[backcolor=transparent];
- [backcolor=transparent] [backcolor=transparent]byte[backcolor=transparent][][backcolor=transparent] buff [backcolor=transparent]=[backcolor=transparent] [backcolor=transparent]new[backcolor=transparent] [backcolor=transparent]byte[backcolor=transparent][[backcolor=transparent]4096[backcolor=transparent]];
- [backcolor=transparent] [backcolor=transparent]StringBuilder[backcolor=transparent] result [backcolor=transparent]=[backcolor=transparent] [backcolor=transparent]new[backcolor=transparent] [backcolor=transparent]StringBuilder[backcolor=transparent]();
- [backcolor=transparent] [backcolor=transparent]while[backcolor=transparent] [backcolor=transparent](([backcolor=transparent]len [backcolor=transparent]=[backcolor=transparent] dis[backcolor=transparent].[backcolor=transparent]read[backcolor=transparent]([backcolor=transparent]buff[backcolor=transparent]))[backcolor=transparent] [backcolor=transparent]!=[backcolor=transparent] [backcolor=transparent]-[backcolor=transparent]1[backcolor=transparent])[backcolor=transparent] [backcolor=transparent]{
- [backcolor=transparent] result[backcolor=transparent].[backcolor=transparent]append[backcolor=transparent]([backcolor=transparent]new[backcolor=transparent] [backcolor=transparent]String[backcolor=transparent]([backcolor=transparent]buff[backcolor=transparent],[backcolor=transparent] [backcolor=transparent]0[backcolor=transparent],[backcolor=transparent] len[backcolor=transparent]));
- [backcolor=transparent] [backcolor=transparent]}
- [backcolor=transparent] [backcolor=transparent]Log[backcolor=transparent].[backcolor=transparent]d[backcolor=transparent]([backcolor=transparent]"OkHttpDns"[backcolor=transparent],[backcolor=transparent] [backcolor=transparent]"Response: "[backcolor=transparent] [backcolor=transparent]+[backcolor=transparent] result[backcolor=transparent].[backcolor=transparent]toString[backcolor=transparent]());
- [backcolor=transparent] [backcolor=transparent]}
- [backcolor=transparent] [backcolor=transparent]});
- [backcolor=transparent]}
以上就是OkHttp+HttpDns实现的全部代码。
3. 总结
相比于通用方案,OkHttp+HttpDns有以下两个主要优势:
- 实现简单,只需通过实现Dns接口即可接入HttpDns服务
- 通用性强,该方案在HTTPS,SNI以及设置Cookie等场景均适用。规避了证书校验,域名检查等环节