个人备案后做淘客网站,深圳制作网站软件,html网页设计论文2000字,精美ppt模板免费下载百度云在我们App开发过程中#xff0c;网络是必不可少的#xff0c;几乎很难想到有哪些app是不需要网络传输的#xff0c;所以网络问题一般都是线下难以复现#xff0c;一旦到了用户手里就会碰到很多疑难杂症#xff0c;所以对于网络的监控是必不可少的#xff0c;针对用户常见…在我们App开发过程中网络是必不可少的几乎很难想到有哪些app是不需要网络传输的所以网络问题一般都是线下难以复现一旦到了用户手里就会碰到很多疑难杂症所以对于网络的监控是必不可少的针对用户常见的问题我们在实际的项目中也需要添加优化策略。
1 网络的基础优化
对于一些主流的网络请求框架像OkHttp、Retrofit等其实就是对Http协议做了封装我们在使用的时候常见的就是POST或者GET请求如果我们是做客户端开发知道这些基本的内容好像也可以写代码但是真正碰到了线上网络问题反而摸不到头脑其实最大的问题还是对于网络方面的知识储备不足所以文章的开始我们先来点基础的网络知识。
1.1 网络连接的类型
其实对于网络的连接我们常见的就是向服务端发起请求服务端返回对应的响应但是在同一时刻只能有一个方向的数据传输这种连接方式称为半双工通信。
类型描述举例单工在通信过程中数据只能由一方发送到另一方常见的例如UDP协议Android广播半双工在通信过程中数据可以由一方A发送到另一方B也可以从一方B发送到另一方A但是同一时刻只能存在一方的数据传输常见的例如Http协议全双工在任意时刻都会存在A到B和B到A的双向数据传输常见的例如Socket协议长连接通道
所以在Http1.0协议时还是半双工的协议因为默认是关闭长连接的如果需要支持长连接那么就需要在http头中添加字段“Connection:Keep-Alive”在Http 1.1协议时默认是开启了长连接如果需要关闭长连接那么需要添加http请求头字段“Connection:close”.
那么什么时候或者场景下需要用到长连接呢其实很简单记住一点即可如果业务场景中对于消息的即时性有要求时就需要与服务端建立长连接例如IM聊天视频通话等场景。
1.2 DNS解析
如果伙伴们在项目中有对网络添加trace日志除了net timeout这种超时错误应该也看到过UnknowHostException这种异常这是因为DNS解析失败没有解析获取到服务器的ip地址。
像我们在家的时候手机或者电脑都会连接路由器的wifi而路由器是能够设置dns服务器地址的 但是如果设置错误或者被攻击篡改就会导致DNS解析失败那么我们app的网络请求都会出现异常所以针对这种情况我们需要加上自己的DNS解析策略。
首先我们先看一个例子假设我们想要请求百度域名获取一个数据例如
object HttpUtil {private const val BASE_URL https://www.baidu.comxxfun initHttp() {val client OkHttpClient.Builder().build()Request.Builder().url(BASE_URL).build().also {kotlin.runCatching {client.newCall(it).execute()}.onFailure {Log.e(OkHttp, initHttp: error $it )}}}
}很明显百度的域名是错误的所以在执行网络请求的时候就会报错
java.net.UnknownHostException: Unable to resolve host www.baidu.comxx: No address associated with hostname所以一旦我们的域名被劫持修改那么整个服务就会处于宕机的状态用户体感就会很差因此我们可以通过OkHttp提供的自定义DNS解析器来做一个小的优化。
public interface Dns {/*** A DNS that uses {link InetAddress#getAllByName} to ask the underlying operating system to* lookup IP addresses. Most custom {link Dns} implementations should delegate to this instance.*/Dns SYSTEM hostname - {if (hostname null) throw new UnknownHostException(hostname null);try {return Arrays.asList(InetAddress.getAllByName(hostname));} catch (NullPointerException e) {UnknownHostException unknownHostException new UnknownHostException(Broken system behaviour for dns lookup of hostname);unknownHostException.initCause(e);throw unknownHostException;}};/*** Returns the IP addresses of {code hostname}, in the order they will be attempted by OkHttp. If* a connection to an address fails, OkHttp will retry the connection with the next address until* either a connection is made, the set of IP addresses is exhausted, or a limit is exceeded.*/ListInetAddress lookup(String hostname) throws UnknownHostException;
}我们看下源码lookup方法相当于在做DNS寻址一旦发生异常那么就会抛出UnknownHostException异常同时内部还定义了一个SYSTEM方法在这个方法中会通过系统提供的InetAddress类进行路由寻址同样如果DNS解析失败那么也会抛出UnknownHostException异常。
所以我们分两步走首先使用系统能力进行路由寻址如果失败那么再走自定义的策略。
class MyDNS : Dns {override fun lookup(hostname: String): MutableListInetAddress {val result mutableListOfInetAddress()var systemAddressList: MutableListInetAddress? null//通过系统DNS解析kotlin.runCatching {systemAddressList Dns.SYSTEM.lookup(hostname)}.onFailure {Log.e(MyDNS, lookup: $it)}if (systemAddressList ! null systemAddressList!!.isNotEmpty()) {result.addAll(systemAddressList!!)} else {//系统DNS解析失败走自定义路由result.add(InetAddress.getByName(www.baidu.com))}return result}
}这样在www.baidu.comxx 解析失败之后就会使用www.baidu.com 域名替换从而避免网络请求失败的问题。
1.3 接口数据适配策略
相信很多伙伴在和服务端调试接口的时候经常会遇到这种情况接口文档标明这个字段为int类型结果返回的是字符串“”或者在某些情况下我需要服务端返回一个空数组但是返回的是null对于这种情况我们在数据解析的时候无论是使用Gson还是Moshi都会解析失败如果处理不得当严重的会造成崩溃。
所以针对这种数据格式不匹配的问题我们可以对Gson简单做一些适配处理例如List类型
class ListTypeAdapter : JsonDeserializerList* {override fun deserialize(json: JsonElement?,typeOfT: Type?,context: JsonDeserializationContext?): List* {return try {if (json?.isJsonArray true) {Gson().fromJson(json, typeOfT)} else {Collections.EMPTY_LIST}} catch (e: Exception) {//Collections.EMPTY_LIST}}
}如果json是List数组类型数据那么就正常将其转换为List数组如果不是那么就解析为空数组。
class StringTypeAdapter : JsonDeserializerString {override fun deserialize(json: JsonElement?,typeOfT: Type?,context: JsonDeserializationContext?): String {return try {if (json?.isJsonPrimitive true) {Gson().fromJson(json, typeOfT)} else {}} catch (e: Exception) {}}
}对于String类型字段首先会判断是否为基础类型StringNumberBoolean如果是基础类型那么就正常转换即可。
GsonBuilder().registerTypeAdapter(Int::class.java, IntTypeAdapter()).registerTypeAdapter(String::class.java, StringTypeAdapter()).registerTypeAdapter(List::class.java, ListTypeAdapter()).create().also {GsonConverterFactory.create(it)}这样在创建GsonConverterFactory时就可以使用我们的策略来进行数据适配但是在测试环境下我们不建议这样使用因为无法发现服务端的问题在上线之后为了规避线上问题可以使用此策略。
2 HTTPS协议
http协议与https协议的区别就是多了一个“s”可别小看这一个“s”它能够保证http数据传输的可靠性那么这个“s”是什么呢就是SSL/TLS协议。 从上图中看在进入TCP协议之前会先走SSL/TLS协议.
2.1 对称加密和非对称加密
既然Https能保证传输的可靠性说明它对数据进行了加密以往http协议数据的传输都是明文传输数据极容易被窃取和冒充因此后续优化中对于数据进行了加密传输才有了Https协议诞生。
常见的加密手段有两种对称加密和非对称加密。
2.1.1 对称加密
首先对称加密从名字就能知道具体的原理看下图 对称加密和解密的密钥是一把钥匙需要双方约定好发送方通过秘钥加密数据接收方使用同一把秘钥解密获取传递的数据。
所以使用对称加密非常简单解析数据很快但是安全性比较差因为双方需要约定同一个keykey的传输有被劫持的风险而统一存储则同样存在被攻击的风险。
所以针对这种情况应运而生出现了非对称加密。
2.1.2 非对称加密
非对称加密会有两把钥匙私钥 公钥对于公钥任何人都可以知道发送方可以使用公钥加密数据而接收方可以用只有自己知道的私钥解密拿到数据。 那么既然公钥所有人都知道那么能够通过公钥直接推算出私钥吗答案是目前不可能未来可能会得看全世界的密码学高手或者黑客能否解决这个问题。
总结一下两种加密方式的优缺点
加密类型优点缺点对称加密流程简单解密速度快不安全秘钥管理有风险非对称加密私钥只有自己知道流程繁琐解密速度慢
2.2 公钥的安全保障
通过2.1小节对于非对称加密的介绍虽然看起来安全性更高了一些但是对于公钥的传递有点儿太理想化我们看下面的场景。 如果公钥在传输的过程中被劫持那么发送方拿到的是黑客的公钥后续所有的数据传输都被劫持了所以问题来了如何保证发送方拿到的公钥一定是接收方的
举个简单的例子我们在马路上捡到了一张银行卡想把里面的钱取出来那么银行柜台其实就是接收方银行卡就是公钥那么银行就会直接把钱给我们了吗肯定不可以要么需要身份证要么需要密码能够证明这个银行卡是我们自己的所以公钥的安全性保证就是CA证书可以理解为我们的身份证。
那么首先接收方需要办一张身份证需要通过CA机构生成一个数字签名具体生成的规则如下 那么最终发送给接收方的就是如下一张数字证书包含的内容有数字签名 公钥 接收方的个人信息等。 那么发送方接收到数字证书之后就会检查数字证书是否合法检测方式如下 如果不是办的假证这种可能性几乎为0因为想要伪造一个域名的数字签名根本不可能CA机构也不是吃干饭的所以只要通过证书认证了那么就能保证公钥的安全性。 2.3 Https的传输流程
其实一个Https请求中间包含了2次Http传输假如我们请求 www.baidu.com 具体流程如下
1客户端向服务端发起请求要访问百度那么此时与百度的服务器建立连接
2此时服务端有公钥和私钥公钥可以发送给客户端然后给客户端发送了一个SSL证书其中包括CA签名、公钥、百度的一些信息详情可见2.2小节最后的图
3客户端在接收到SSL证书后对CA签名解密判断证书是否合法如果不合法那么就断开此次连接如果合法那么就生成一个随机数作为数据对称加密的密钥通过公钥加密发送到服务端。
4服务端接收到了客户端加密数据后通过私钥解密拿到了对称加密的密钥然后将百度相关数据通过对称加密秘钥加密发送到客户端。
5客户端通过解密拿到了服务端的数据此次请求结束。
其实Https请求并不是完全是非对称加密而是集各家之所长因为对称加密密钥传递有风险因此前期通过非对称加密传递对称加密密钥后续数据传递都是通过对称加密提高了数据解析的效率。
但是我们需要了解的是Https保障的只是通信双方当事人的安全像测试伙伴通过Charles抓包这种中间人攻击方式还是会导致数据泄露的风险因为通过伪造证书或者不受信任的CA就可以实现。
Android 学习笔录
OkHttp 源码解析笔记https://qr18.cn/Cw0pBD Android 性能优化篇https://qr18.cn/FVlo89 Android 车载篇https://qr18.cn/F05ZCM Android 逆向安全学习笔记https://qr18.cn/CQ5TcL Android Framework底层原理篇https://qr18.cn/AQpN4J Android 音视频篇https://qr18.cn/Ei3VPD Jetpack全家桶篇内含Composehttps://qr18.cn/A0gajp Kotlin 篇https://qr18.cn/CdjtAF Gradle 篇https://qr18.cn/DzrmMB Flutter 篇https://qr18.cn/DIvKma Android 八大知识体https://qr18.cn/CyxarU Android 核心笔记https://qr21.cn/CaZQLo Android 往年面试题锦https://qr18.cn/CKV8OZ 2023年最新Android 面试题集https://qr18.cn/CgxrRy Android 车载开发岗位面试习题https://qr18.cn/FTlyCJ 音视频面试题锦https://qr18.cn/AcV6Ap