概述
一次网络请求的操作,是从DNS解析开始,建立连接并发送数据到服务端,然后读取服务端返回的数据,最后释放连接。
DNS解析优化
安全方面
DNS指的是,域名解析
,我们访问一个域名,实际上是访问的它对应的ip地址,DNS实际上就是 将域名解析成ip的过程。
DNS的过程之所以能够被劫持,是因为解析过程中,如果遇到了中间人劫持,就有可能返回给你一个 恶意的IP地址。
通常的解决方案是,HttpDps,它只是一个概念,并不是一个现成的开源库。它与传统DNS解析的区别在于,HttpDns会绕过运营商的DNS服务器,直接与DNS服务器80端口连接,有效防止域名劫持。
阿里云和腾讯云已经实现了这种功能,但是都是收费的,所以 PASS.
普通开发者可以用 七牛
的免费Happy-DNS.
OkHttp已经预留了 dns设置的接口。
我们需要实现的是 上图中的loopUp接口,上面红框中的SYSTEM,是系统给我们默认的DNS解析器。
添加依赖库:
然后自己实现一个DNS的实现类:
最后将这个HttpDns设置给okhttp即可。
java
OkHttpClient client = new OkHttpClient.Builder()
.dns(new HttpDns())
// 其他配置
.build();
速度方面
DNS解析需要连接到 DNS服务器,服务器去帮我们查询具体的ip然后再给到我们,这个过程是会耗费一定时间的。
是不是每次都要去DNS服务器请求ip地址? 不一定吧。当http服务发布以后,ip地址很少会有大规模的变化。所以,我们可以缓存域名和ip的对应关系到本地,请求dps服务器之前,先看本地缓存,本地没有缓存再去走dns服务器。 这个也可以称为 IP直连方式
,但是这种方式成本较高,我们需要在本地维护一套 域名IP对应机制,另外,HTTPS的访问要求证书绑定域名,在执行https请求时,客户端需要保存以及解析证书,这部分工作成本也较大。
如果我们正在请求一个 http请求时,如果网络设备切换路由,就有可能出现dns解析超时的情况。很久以后会抛出 UnknownHostException
,并且 okhttp 设置的超时时间对这种情况不起作用。
这种情况,可以在自定义DNS中做超时判断,
这里利用了 Java新特性中的Future,如果一个任务在一定时间内没有执行完毕,就抛出异常。
网络请求缓存优化
请求失败
当一个网络请求执行失败之后,将请求本身缓存在本地,稍后尝试重新发送。
请求成功
网络请求成功之后,将返回的数据以及请求用键值对的方式缓存在本地。下一次执行相同的请求,先展示缓存的数据,当新数据到来之后,再对比新旧数据,如果有差异,则展示新数据。
以下是一些示范(只是展示思想,不要照搬):
上图是利用的 dao.insertOrReplace();
dao指的是数据库的映射
。 图中1处,将网络请求本身以及相关参数 设置到 httpDataCache
对象中去, 图中2处,将缓存数据转化成json字符串,并设置到 httpDataCache
图中3处,将 httpDataCache
提交到 数据库。
数据库的结构如下:
而在网络层代码中,在执行网络请求之前,先尝试从数据库中取出 当前请求的缓存结果,展示在界面上,然后去请求网络,并且在请求成功之后,将 结果再次缓存。大概如下:
幂等性
当我们点外卖付款时,我们付钱,服务端收钱,服务端收钱成功之后,要向我们发送一条消息告诉我们付款成功了。但是如果由于网络原因,这条消息没有发送成功。我们就有可能再次付款。
这就涉及到网络请求的幂等性(一次和多次请求某一资源应该具有同样的影响)。
实现幂等性,需要客户端和服务器一起改造。
- 唯一标识符(Unique Identifier):每次请求都附带一个唯一标识符或者请求 ID,服务端通过这个标识符来判断是否是重复请求。如果服务端已经处理过具有相同标识符的请求,它可以忽略重复的请求。
- 乐观锁(Optimistic Locking):在进行修改操作时,记录一个版本号或时间戳,每次请求都携带这个版本号或时间戳。当服务端收到请求时,它会检查当前数据的版本号是否与请求中携带的版本号一致,如果一致则执行操作,否则拒绝请求。
- 幂等性接口设计:设计接口时遵循幂等性原则,保证相同的请求在多次执行时不会产生不同的结果。例如,GET 请求通常具有幂等性,因为多次执行相同的 GET 请求不会改变资源的状态。
综上所述,网络请求的幂等性是一种很重要的特性,能够确保在复杂的网络环境中请求的可靠性和数据的一致性。合理设计和处理网络请求,遵循幂等性原则有助于提高系统的可靠性和稳定性。