使用Okhttp代理本机网络请求并指定域名解析方案

一.应用背景

        我们是一个嵌入式设备,需要联网调用一些接口来请求数据,最近在项目开发中遇到这样一个需求:设备可能会在类似校园、政府等地使用,这些地点可能会限制IP访问,需要设置固定IP才可以使用。当看到这个需求的时候我第一反应这个问题好简单啊,这还不分分钟搞定的事,于是我就让我的同事弄了个路由器模拟了一下这种网络环境,把DHCP禁用,只允许部分IP通行。

        我们设备是通过一个模块来分配IP的,于是翻出来模块说明书,找到设置WAN口模式的命令,咔咔咔三下五除二,搞定,查询路由器连接,嗯,是我设置的固定IP,嘿嘿嘿,我真是个大聪明,这就搞定了。结果打脸来的太早,访问接口,不通!

        

二.故障原因

        开始以为是路由器配置问题,但是人家电脑自己设置成固定IP上网飞快,这就见了鬼了,后来仔细回忆了下网络请求的原理,啧,还有DNS解析域名这回事呢。正常来说,你的模块如果提供了设置固定IP的功能,那DNS这块肯定会帮你处理,结果我们就赶上这种定制设备的不成熟了。于是找到厂家要求增加DNS设置功能,厂家说好,你们准备订购多少设备来着?300-500,厂家:哦,那您排期慢一些,您就等吧~

三.解决办法

        没办法,时间紧任务急,我是开发小能手我来抗(手动狗头),分析问题,现在可以确定的是设置固定IP后,本机默认的DNS失效了,那就从这条线去寻找解决办法吧。

        首先确认的是,项目中网络请求的部分,全部是由Okhttp代理的,嗯,那就好办了,不用处处改了。

        查阅Okhttp文档可知,人家本来就支持手动设置自己的域名解析方法:

    /**
     * Sets the DNS service used to lookup IP addresses for hostnames.
     *
     * If unset, the [system-wide default][Dns.SYSTEM] DNS will be used.
     */
    fun dns(dns: Dns) = apply {
      if (dns != this.dns) {
        this.routeDatabase = null
      }
      this.dns = dns
    }

那就简单的一批了,直接自己写一个域名解析对象,设置一下就OK了,下面直接贴出方法:

/**
 * @Author LiuQN
 * @Date 2024/8/1 15:24
 */
public class CustomDns implements Dns {
    @NonNull
    @Override
    public List<InetAddress> lookup(@NonNull String hostname) throws UnknownHostException {
        LogUtil.e("test_dns", "开启阿里公共DNS解析,目标:" + hostname);
        if (hostname.contains("www.baidu.com")) {
            DNSResolver.setSchemaType(DNSResolver.HTTP);
        } else {
            DNSResolver.setSchemaType(DNSResolver.HTTPS);
        }
        String[] ipArr = DNSResolver.getInstance().getIPsV4ByHost(hostname);
        LogUtil.e("test_dns", "开启阿里公共DNS解析,IP:" + BaseJson.toJson(ipArr));
        if (0 == ipArr.length) {
            return Collections.emptyList();
        }
        List<InetAddress> inetAddressList = new ArrayList<>(ipArr.length);
        for (String ip : ipArr) {
            if ("0".equals(ip)) {
                continue;
            }
            try {
                InetAddress inetAddress = InetAddress.getByName(ip);
                inetAddressList.add(inetAddress);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return inetAddressList;
    }
}

然后初始化OkHttpClient对象:

OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.dns(new CustomDns());

其中,lookup就是解析域名要手动实现的部分。我这里选择的是阿里的公共解析,每月有1000万次免费解析(不过https一次解析算5次,这就是为啥我里面ping百度的操作指定了使用http模式解析,能省一点是一点),如果不想使用阿里公共DNS解析(不想花钱),那就替换lookup中的方法,手动将你的域名提交到免费DNS解析服务上(比如8.8.8.8,114.114.114.114等),然后将返回的的IP做成InetAddress对象,return即可,这就是DNS解析的原理,不过阿里更快一些吧,预算充足的话可以考虑,稳定、安全、嵌入简单,其实也没多少钱~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值