App线上网络问题优化策略

这篇具有很好参考价值的文章主要介绍了App线上网络问题优化策略。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在我们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服务器地址的,

App线上网络问题优化策略,移动开发,Android,性能优化,网络,android,移动开发,安卓,面试,性能优化

但是如果设置错误,或者被攻击篡改,就会导致DNS解析失败,那么我们app的网络请求都会出现异常,所以针对这种情况,我们需要加上自己的DNS解析策略。

首先我们先看一个例子,假设我们想要请求百度域名获取一个数据,例如:

object HttpUtil {

    private const val BASE_URL = "https://www.baidu.comxx"

    fun 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.
   */
  List<InetAddress> lookup(String hostname) throws UnknownHostException;
}

我们看下源码,lookup方法相当于在做DNS寻址,一旦发生异常那么就会抛出UnknownHostException异常;同时内部还定义了一个SYSTEM方法,在这个方法中会通过系统提供的InetAddress类进行路由寻址,同样如果DNS解析失败,那么也会抛出UnknownHostException异常。

所以我们分两步走,首先使用系统能力进行路由寻址,如果失败,那么再走自定义的策略。

class MyDNS : Dns {


    override fun lookup(hostname: String): MutableList<InetAddress> {

        val result = mutableListOf<InetAddress>()
        var systemAddressList: MutableList<InetAddress>? = 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 : JsonDeserializer<List<*>> {
    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 : JsonDeserializer<String> {

    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类型字段,首先会判断是否为基础类型(String,Number,Boolean),如果是基础类型那么就正常转换即可。

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协议。

App线上网络问题优化策略,移动开发,Android,性能优化,网络,android,移动开发,安卓,面试,性能优化

从上图中看,在进入TCP协议之前会先走SSL/TLS协议.

2.1 对称加密和非对称加密

既然Https能保证传输的可靠性,说明它对数据进行了加密,以往http协议数据的传输都是明文传输,数据极容易被窃取和冒充,因此后续优化中,对于数据进行了加密传输,才有了Https协议诞生。

常见的加密手段有两种:对称加密和非对称加密。

2.1.1 对称加密

首先对称加密,从名字就能知道具体的原理,看下图:

App线上网络问题优化策略,移动开发,Android,性能优化,网络,android,移动开发,安卓,面试,性能优化

对称加密和解密的密钥是一把钥匙,需要双方约定好,发送方通过秘钥加密数据,接收方使用同一把秘钥解密获取传递的数据。

所以使用对称加密非常简单,解析数据很快,但是安全性比较差,因为双方需要约定同一个key,key的传输有被劫持的风险,而统一存储则同样存在被攻击的风险。

所以针对这种情况,应运而生出现了非对称加密。

2.1.2 非对称加密

非对称加密会有两把钥匙:私钥 + 公钥,对于公钥任何人都可以知道,发送方可以使用公钥加密数据,而接收方可以用只有自己知道的私钥解密拿到数据。

App线上网络问题优化策略,移动开发,Android,性能优化,网络,android,移动开发,安卓,面试,性能优化

那么既然公钥所有人都知道,那么能够通过公钥直接推算出私钥吗?答案是目前不可能,未来可能会,得看全世界的密码学高手或者黑客能否解决这个问题。

总结一下两种加密方式的优缺点:

加密类型 优点 缺点
对称加密 流程简单,解密速度快 不安全,秘钥管理有风险
非对称加密 私钥只有自己知道 流程繁琐,解密速度慢

2.2 公钥的安全保障

通过2.1小节对于非对称加密的介绍,虽然看起来安全性更高了一些,但是对于公钥的传递有点儿太理想化,我们看下面的场景。

App线上网络问题优化策略,移动开发,Android,性能优化,网络,android,移动开发,安卓,面试,性能优化

如果公钥在传输的过程中被劫持,那么发送方拿到的是黑客的公钥,后续所有的数据传输都被劫持了,所以问题来了,如何保证发送方拿到的公钥一定是接收方的?

举个简单的例子:我们在马路上捡到了一张银行卡,想把里面的钱取出来,那么银行柜台其实就是接收方,银行卡就是公钥,那么银行就会直接把钱给我们了吗?肯定不可以,要么需要身份证,要么需要密码,能够证明这个银行卡是我们自己的,所以公钥的安全性保证就是CA证书(可以理解为我们的身份证)。

那么首先接收方需要办一张身份证,需要通过CA机构生成一个数字签名,具体生成的规则如下:

App线上网络问题优化策略,移动开发,Android,性能优化,网络,android,移动开发,安卓,面试,性能优化

那么最终发送给接收方的就是如下一张数字证书,包含的内容有:数字签名 + 公钥 + 接收方的个人信息等。

App线上网络问题优化策略,移动开发,Android,性能优化,网络,android,移动开发,安卓,面试,性能优化

那么发送方接收到数字证书之后,就会检查数字证书是否合法,检测方式如下:

App线上网络问题优化策略,移动开发,Android,性能优化,网络,android,移动开发,安卓,面试,性能优化

如果不是办的假证,这种可能性几乎为0,因为想要伪造一个域名的数字签名,根本不可能,CA机构也不是吃干饭的,所以只要通过证书认证了,那么就能保证公钥的安全性。

App线上网络问题优化策略,移动开发,Android,性能优化,网络,android,移动开发,安卓,面试,性能优化

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全家桶篇(内含Compose):https://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文章来源地址https://www.toymoban.com/news/detail-703143.html

到了这里,关于App线上网络问题优化策略的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Aidex 移动端快速开发框架# RuoYi-Uniapp项目,uniapp vue app项目跨域问题

     参考地址: manifest.json官方配置文档:manifest.json 应用配置 | uni-app官网 Chrome 调试跨域问题解决方案之插件篇: uni-app H5跨域问题解决方案(CORS、Cross-Origin) - DCloud问答 其实uni-app官方有解决跨域的办法,官方推荐使用HBuilderX中内置的浏览器去预览,在内置的浏览器中不会存

    2024年02月11日
    浏览(27)
  • [Android][WIFI]手机作AP,关闭移动网络后,STA端断开重连问题分析

    测试平台 Android版本:Android P(9.0) 复现步骤 准备两台移动设备,一台作为AP,一台作为STA; 作为AP的设备具备移动网络上网,热点网络分享能力; 打开作为AP的设备的移动网络流量开关,再打开热点; 作为STA的设备接入该AP,并等待其通路判断完成,确保Internet网络访问能力正

    2024年02月10日
    浏览(49)
  • Android 开发板接入外接USB键盘App重启问题

    前言 在Android 9.0的项目中,测试工程师验证问题时插入某些USB的无线鼠标,会导致当前的APK会销毁然后重启一次,重新走一次生命周期。 Activity为啥会重启? 为什么会重启? 我们大概率的知道,一般App重启大致有如下原因: APP异常了(微信存在这样的问题,闪退重启) 机器

    2024年02月11日
    浏览(28)
  • 记一次线上问题 → Deadlock 的分析与优化

    今天女朋友很生气 女朋友:我发现你们男的,都挺单纯的 我:这话怎么说 女朋友:脑袋里就只想三件事,搞钱,跟谁喝点,还有这娘们真好看 我:你错了,其实我们男人吧,每天只合计一件事 女朋友:啥事呀? 我:这娘们真好看,得搞钱跟她喝点   MySQL8. 0.30  ,隔离级别

    2024年02月15日
    浏览(38)
  • 开发Android App,令人头疼的Android Studio、Gradle、JDK、Andrroid Gradle Plugin版本问题

    开发Android App,各种报错。真是炼狱般的体验,一弄弄一天,一抬头半夜两点半,时间废了还没成果,真是服了。 记录下问题,便于后期查阅。 看到网友搞笑评论:Gradle 在不做人方面,一直很稳定 Android Studio 版本:Flamingo | 2022.2.1 Patch 1 默认支持的JDK: 默认自带的 JDK 17 创建

    2024年01月25日
    浏览(46)
  • 移动应用安全策略不足:未对通过移动应用访问网络的安全进行适当管理

    随着移动互联网的快速发展,越来越多的企业和个人选择通过移动应用来访问网络资源。然而,移动应用安全策略的不足,往往导致数据泄露、恶意攻击等问题。本文将针对这一问题进行分析并提出相应的解决方案。 1. 数据泄露 由于移动设备缺乏与PC机一样的物理隔离机制,

    2024年02月01日
    浏览(41)
  • java计算机毕业设计基于安卓Android/微信小程序的食堂线上预约点餐系统APP

    我们生活的各个领域都涉及到计算机的应用,其中包括食堂线上预约点餐系统的网络应用,在外国线上管理系统已经是很普遍的方式,不过国内的线上管理系统可能还处于起步阶段。食堂线上预约点餐系统具有食堂线上预约点餐信息管理功能的选择。食堂线上预约点餐系统采

    2024年02月09日
    浏览(56)
  • uniapp 移动端app判断用户app版本是否是最新版(Android)

    1.在uniapp项目中的App.vue文件下 2. 具体实现代码 ios的话自行给提示 去应用商店下载

    2024年01月20日
    浏览(43)
  • Android:安卓开发采用Volley网络框架+MySQL数据库,实现从服务器获取数据并展示完成记单词APP

    实现功能:设计一个记单词APP。服务器采用Tomcat,数据库采用Mysql。实现用户的注册登录功能以及单词的增删改查。 指标要求:实现UI布局;将系统数据保存到Mysql数据库中,并采用Volley网络框架实现从服务器获取数据并展示。 步骤1:搭建开发环境。 步骤2:准备资源。 步骤

    2024年02月13日
    浏览(36)
  • Android 性能优化——APP启动优化

            首先在《Android系统和APP启动流程》中我们介绍了 APP 的启动流程,但都是 FW 层的流程,这里我们主要分析一下在 APP 中的启动流程。要了解 APP 层的启动流程,首先要了解 APP 启动的分类。 冷启动         应用从头开始启动,即应用的首次启动。需要做大量的工

    2024年04月12日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包