如何开发一款安全高效的Android网络库(详细教程)

根据很多网友及项目需要,我们针对Retrofit做了一层简单封装,包含了很多可插拔的功能,能够适应大多数项目的需要,这一期我们来分析以下如何设计一款安全高效的Android网络库——FlexNet

1. 网络框架模块

在设计网络之前,需要首先考虑网络库的模块划分:

网络模块.jpg

上图是通用网络库需要考虑的模块,下面结合我们的通用封装来筛选并设计所需模块。

1.1 底层网络请求库

在选择底层网络请求库时,考虑到目前市场上已经存在多种成熟的开源库,如OkHttp、Retrofit和Volley,大可不必自研,选择一个可靠且高效的底层网络内核是构建网络库的基础。目前,Retrofit和OkHttp是最常用的选择:

  • Retrofit 提供了便捷的API定义方式和数据解析能力。
  • OkHttp 则作为底层HTTP客户端,负责实际的网络通信。

结合各个库的优缺点以及使用情况,FlexNet当前基于Retrofit来开发。库选择好之后还要设计封装方式,为了确保灵活性,便于将来平滑快速切换到其他底层库,需要考虑以下问题:

  1. 设计统一封装接口:将底层网络请求库的关键功能封装在一个统一的接口中,以便于后续更换底层库时只需要修改这个接口的实现即可。这样做可以减少对其他部分代码的影响,提高切换的便捷性;
  2. 提供通用的配置参数:确保接口设计时能够接受和传递通用的配置参数,例如超时时间、缓存策略、拦截器等。这样即使切换到其他底层库,也能够充分利用这些配置参数,减少对代码的修改;
  3. 保持一致的数据返回格式:确保底层库的接口设计在数据返回格式上保持一致,这样在切换底层库时,上层代码对返回数据的处理方式可以保持不变;
  4. 及时更新文档和示例代码:为了方便后续开发人员接入或者切换底层库,需要编写一份详细的使用文档,并提供示例代码来演示如何使用FlexNet的接口和配置。这样可以加快新开发人员上手的速度,减少学习和使用的难度。

1.2 请求/响应格式

在1.1小节提到过,请求和响应的统一是解耦的必要步骤。请求和响应的格式也是网络库设计中的重要部分。

1. Request

网络返回的数据需要进行一定的处理,以便处理错误和正常情况。这些处理包括日志打印、埋点上报,或者将数据返回给业务方便于问题定位。为了满足这些需求,我们对Response进行了封装:

data class SongListReq(val pageNum: Int = 1, val pageSize: Int = 20, val sourceType: String = SOURCE_QQ
) {companion object {const val SOURCE_QQ = "QQ"}
}
2. Response

网络返回的数据需要针对错误、正常做一些处理,比如日志打印、埋点上报,或者返回给业务方便于定位问题,所以这里对Response做了一层封装:

sealed class ResponseEntity<T>(val body: T?, val code: Int, val msg: String)

可以看到,ResponseEntity是一个sealed类型。首先,我们定义了ErrorSuccess两个子类,然后根据不同的错误和成功类型,派生出了不同的响应类,业务方拿到Response之后可以根据类型来做相应处理。

为了增强扩展性与向下兼容性,也可以直接使用Raw数据对象,或者JsonObject对象来处理,这样就需要自行处理成功和失败,及区分失败类型。

1.3 错误处理

良好的错误处理机制能够提高开发体验和应用稳定性:

  • 统一错误处理: 捕获网络请求中的所有异常,并将其转换为友好的错误信息。
  • 错误类型分类: 根据HTTP状态码、网络异常和业务逻辑错误进行详细分类。
  • 回调和事件总线: 提供错误处理回调或通过事件总线(如EventBus)分发错误信息。

成功的方式千篇一律,失败的原因千差万别。在拿到Http Response之后,我们需要对响应做一些包装,方便区分成功和失败的原因,并给出提示。首先定义了包含失败和错误的返回码:

CODE_SUCCESS10000请求成功,数据来源网络
CODE_SUCCESS_CACHE10001返回成功,数据来源于本地缓存
CODE_SUCCESS_BODY_NULL10002请求成功,但消息体为空
CODE_ERROR_UNKNOWN-200未知错误
CODE_ERROR_UNKNOWN_HOST-201host解析失败,无网络也属于其中
CODE_ERROR_NO_NETWORK-202无网络
Http的错误直接透传

针对每一种错误都定义了一个ResponseEntity类型,可以通过类型或者code判断错误类型,通过msg获取错误信息

1.4 请求方法

网络库需要全面支持各种HTTP请求方法:

  • GET: 获取资源。
  • POST: 提交数据并创建新资源。
  • PUT/PATCH: 更新现有资源。
  • DELETE: 删除资源。
  • HEAD/OPTIONS: 获取资源元数据和支持的方法。

确保库能够方便地配置和使用这些方法,并提供灵活的参数传递方式。

FlexNet沿用Retrofit的方式,通过注解完成请求方法的声明:

/** 获取音乐分类列表 */
@POST("api/cloudxcar/atmos/v1/category/page/list")
suspend fun getSongList(@Body body: SongListReq): ResponseEntity<MusicResponse<SongListRsp>>

为了方便后续扩展,需要对业务方做一定的限制,接口类必须实现IServerApi接口

1.5 SSL证书验证

证书认证确保网络通信的安全性:

  • 双向认证: 配置客户端和服务器之间的双向SSL认证,以防止中间人攻击。
  • 证书锁定: 实现证书锁定(Pinning),只信任指定的证书或公钥。
  • 自签名证书: 支持自签名证书的配置和使用。

为了方便App使用,我们的网络库集成了“ssllib”双向认证,大家可以自行在项目中添加公司或者个人的双向认证功能。在实现双向认证时,我们需要考虑以下两个方面:

  1. 提供双向认证开关:我们为用户提供了一个总开关,以及每个接口单独的开关。这样,用户可以根据实际需求选择是否开启双向认证。
  2. 处理启动过早导致的验证失败:有些App启动时机太早可能导致验证失败。为了解决这个问题,我们还提供了一个主动验证的接口,使得用户可以在合适的时机手动触发验证操作。

关于双向认证的描述及使用参考:双向认证

1.6 文件操作

网络还需要考虑文件的上传和下载功能:

  • 文件上传: 实现多部件表单数据上传,支持大文件分块上传。
  • 文件下载: 提供断点续传功能,确保下载过程的稳定性和可靠性。
  • 进度显示: 提供上传和下载进度的实时反馈。

下载最基本的接口:

  • onProgressUpdated: 下载进度回调,回传当前已下载大小和文件总大小
  • onDownloadFailed: 下载失败回调,回传失败原因
  • onDownloadCompleted: 下载完成回调,回传下载成功的File对象

1.7 数据缓存

  1. 数据缓存策略
  2. 缓存容量
  3. 持久化方式
  4. 更新策略
  5. 失效处理
  6. 删除数据缓存

1.8 拦截器

Interceptor可用于拦截并处理网络请求和响应,利用它可以在发送请求之前和接收响应之后对其进行自定义操作和处理。Interceptor可用于添加、修改、删除请求头信息、记录日志、进行权限验证、缓存响应等功能。

目前FlexNet默认实现了3种拦截器,也是在网络库中常用的拦截器:

  • 请求拦截器: 添加公共请求头、参数签名等。
  • 响应拦截器: 处理通用的响应逻辑,如统一解析包装的响应数据。
  • 日志拦截器: 打印详细的请求和响应日志,方便调试和问题定位。

1.9 扩展功能

为了增强网络库的灵活性和可扩展性,可以提供一些扩展功能:

  • 插件机制: 允许开发者通过插件机制扩展库的功能,而无需修改核心代码。
  • 灵活配置: 提供丰富的配置选项,以满足不同项目的需求,如超时时间设置、重试策略等。
  • 模块化设计: 将核心功能与扩展功能模块化,开发者可以按需引入所需模块。

2. App网络接口设计

2.1 Data Access Layer

这一层通常会设计一个DAO

DAO即Data-Access-Object,直译过来就是数据访问对象。很多人对DAO的理解是负责链接数据库,实际上并不一定。它更应该被理解为一个接口,一个DAL的实现,可能连接数据库,也可能连接到Redis,或者文件

通常一个Model 对应一个DAO。比如Account –> AccountDAO; User–> UserDAO

比如常见的DAO是这样:

public interface MusicDAO {Account get(String songName);void create(MusicInfo info);void update(MusicInfo info);void delete(String songName);
}

内部的实现可对接不同的数据源

2.2 Repository

Repository用于封装数据访问和 持久化 的细节。Repository层提供了一种统一的接口,用于获取和存储数据,并隐藏了底层数据访问技术的具体实现细节。它负责从数据源(如数据库、网络等)中获取数据,并将数据转化为应用程序可以直接使用的形式。Repository层的设计目标是对上层提供简单、统一的数据访问方式,同时可以灵活地切换底层数据源的具体实现。

Repository相对DAO层级更高,更抽象。一个Repository对应一个Domain,作为对外的唯一接口。

如:

object WeatherRepo : BaseRepo<WeatherApi>() {suspend fun getWeather(): JsonObject {return mRepo.getWeather()}override val baseUrl = "https://v0.yiketianqi.com/"override val mutualAuthSwitch = false
}

3. 接入方式

网络库接入方式:FlexNet 网络库接入文档

4. 后续工作

  1. 目前还有一些和okHttp、Retrofit的耦合,后续需要彻底解耦

  2. Java接口适配

  3. 完善胶水层

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/27210.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习的舌象诊断:从舌头上了解系统性疾病!

首先 深度学习算法能否解决东方医学中依靠医生经验的诊断问题&#xff1f;而要实现这个目标&#xff0c;需要什么呢&#xff1f; 用舌头诊断被称为口腔健康的指标&#xff0c;但在东方医学中&#xff0c;舌头也被用来评估全身的状况。换句话说&#xff0c;通过分析舌头的图像…

【leetcode--单词规律】

题目要求&#xff1a; 跟上一个字符串的思路一致&#xff0c;只是要进行单词的拆分&#xff0c;用.split()函数即可。 class Solution:def wordPattern(self, pattern: str, s: str) -> bool:word s.split()if(len(pattern) ! len(word)):return Falsereturn len(set(patt…

火爆全网《pvz植物大战僵尸杂交版》最新安装包,支持Android、Windows、iOS!

我是阿星&#xff0c;今天跟大家聊聊最近在B站火得一塌糊涂的老游戏——《植物大战僵尸》。你没听错&#xff0c;就是那个曾经让我们熬夜奋战&#xff0c;一关又一关的游戏。 话说回来&#xff0c;这游戏怎么就突然又火起来了呢&#xff1f; 原来&#xff0c;是因为它的最新整…

关于2024年第一批计算机程序设计员(Python)四级、三级职业技能等级证书认证考试的通知

计算机程序设计员&#xff08;Python&#xff09;详细介绍 报名详细信息&#xff1a; 报名截止时间&#xff1a;2024年6月05日 ~ 2024年6月18日 准考证下载时间&#xff1a;2023年6月24日 ~ 6月28日 考试时间&#xff1a;2024年6月29日 四级&#xff1a;08:30~12:30&#…

除了广告和卖货,还有这12种盈利方式

如何让产品赚得更多的钱是永恒的话题&#xff0c;产品的盈利方式也层出不穷。目的是让我们的产品走向商业化&#xff0c;达到变现&#xff0c;不断地更新迭代&#xff0c;发展下去。 本文介绍了产品的12种盈利方式&#xff1a;延迟、便利、图像清晰度、界面、操作速度、灵活性、…

【CS.AL】算法复杂度分析 —— 渐进符号表示法

文章目录 1 概述2 渐进符号详解2.1 大O符号&#xff08;O&#xff09;2.2 Ω符号&#xff08;Ω&#xff09;2.3 Θ符号&#xff08;Θ&#xff09;2.4 o符号&#xff08;o&#xff09;2.5 ω符号&#xff08;ω&#xff09; 3 具体例子3.1 插入排序&#xff08;Insertion Sort…

【论文阅读】《Sketch and Refine: Towards Fast and Accurate Lane Detection》

Abstract 车道检测是指确定道路上车道的精确位置和形状。尽管目前的方法已经做出了努力&#xff0c;但由于现实世界场景的复杂性&#xff0c;这仍然是一项具有挑战性的任务。无论是基于建议的方法还是基于关键点的方法&#xff0c;现有方法都无法有效、高效地描绘车道。基于建…

程序猿大战Python——容器——知识补充

字典遍历方法 目标&#xff1a;了解遍历字典的遍历方法。 当要遍历字典的元素内容&#xff0c;即获取字典的键、值。 常用方法&#xff1a; 函数名含义keys()以列表的形式&#xff0c;返回一个字典所有的键。values()以列表的形式&#xff0c;返回一个字典所有的值。items()返…

C++11初始化列表打包器initializer_list

有时我们无法提前知道应该向函数传递几个实参。为了编写能处理不同数量实参的函数我们使用initializer_list Cplusplus中的定义&#xff1a; 其里面有三个成员函数 也就是说他是支持迭代器的&#xff0c;支持迭代器就支持范围for 图像理解 函数类型 void Test1_initializer_li…

在微信小程序中安装和使用vant框架

目录 1、初始化项目2、安装vant相关依赖3、修改 app.json4、修改 project.config.json5、构建npm6、使用示例 本文将详细介绍如何在微信小程序中安装并使用vant框架&#xff5e; 开发工具&#xff1a;微信开发者工具 1、初始化项目 从终端进入小程序项目目录&#xff0c;执行…

JDK8时间类,时区,时间和格式化

一.时间类 二.获取所有的时区 1.获取所有的时区Set<String> zoneIds ZoneId.getAvailableZoneIds();System.out.println(zoneIds.size()); 根据打印的结果可以看到java类中一共有603个时区。 三.获取当前系统默认的时区 ZoneId zoneId ZoneId.systemDefault();Syste…

linux搭建harbor镜像仓库

安装docker-compose&#xff1a;安装docker-compose_安装 docker-compose-CSDN博客 安装harbor&#xff0c;我安装的是v2.4.3 #下载安装包 wget https://github.com/goharbor/harbor/releases/download/v2.4.3/harbor-offline-installer-v2.4.3.tgz#解压 tar -zxvf harbor-off…

618全面开战,抖音电商头部品牌罗拉密码突然“不干”了?

前言&#xff1a; 随着618电商大战的硝烟渐浓&#xff0c;各大电商平台纷纷摩拳擦掌&#xff0c;准备在这场年度购物盛宴中大展拳脚。然而&#xff0c;在这热闹非凡的氛围中&#xff0c;一个熟悉的名字却显得格外低调——罗拉密码。作为抖音电商领域的头部品牌&#xff0c;罗拉…

文心智能体体验,打造你自己的GPTs应用

利用百度智能体搭建的《RPG冒险游戏大作战》已经发布啦&#xff01; RPG冒险游戏大作战 玩家扮演一位小小勇士女孩&#xff0c;从被巨龙毁灭的冒险小镇出发&#xff0c;一路披荆斩棘&#xff0c;集齐四件神器后&#xff0c;打败巨龙&#xff0c;夺回小镇的安宁&#xff01; 整…

常见机器学习的原理及优略势

有监督 一、线性回归&#xff08;Linear Regression) 1. 算法原理 线性回归&#xff08;Linear Regression&#xff09;是一种基本的回归算法&#xff0c;它通过拟合一个线性模型来预测连续型目标变量。线性回归模型的基本形式是&#xff1a;y w1 * x1 w2 * x2 … wn * …

Java_中间件——Redis

Redis 介绍&#xff1a; Redis是一个基于内存的key-value结构数据库&#xff08;MySQL是通过数据文件方式存储在磁盘上&#xff0c;数据结构是二维表&#xff09; 特点&#xff1a; 更改配置文件&#xff1a; 使用密码&#xff1a; redis默认是不需要密码的&#xff0c;如果…

2024全国大学生信息安全竞赛(ciscn)半决赛(华南赛区)Pwn题解

前言 找华南赛区的师傅要了一份半决赛的Pwn题&#xff0c;听说只有一道题。 题目很简单&#xff0c;可以申请任意大小chunk&#xff0c;并存在UAF、DoubleFree漏洞。 还给了后门函数&#xff0c;不过限制是edit只能写8字节的数据到chunk中。 MyHeap 逆向分析 拖入IDA分析…

Linux--MQTT简介

一、简介 MQTT &#xff08; Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输&#xff09;&#xff0c; 是一种基于客户端服务端架构的发布/订阅模式的消息传输协议。 与 HTTP 协议一样&#xff0c; MQTT 协议也是应用层协议&#xff0c;工作在 TCP/IP 四…

计算机系统的主要概念

这篇文章通过研究“hello&#xff0c;world”这个简单程序的生命周期来介绍计算机系统的主要概念。 1. 信息就是位 上下文 我们以 hello 程序为例&#xff0c;在 linux 系统中&#xff0c;我们编辑文本文件 hello.c&#xff0c;使用编译器将其编译成可执行的 源程序&#xf…