ITKeyword,专注技术干货聚合推荐

注册 | 登录

App架构设计经验谈

snjianrong 分享于 2016-02-20

推荐:移动App架构设计

移动App架构设计 本文主要总结了几种常用的架构模式, 基本是层层递进的转载请注名出处 http://blog.csdn.net/uxyheaven, 良好的排版在https://github.com/uxyhea

2019阿里云全部产品优惠券(新购或升级都可以使用,强烈推荐)
领取地址https://promotion.aliyun.com/ntms/yunparter/invite.html

转载自Keegan小钢 1.App架构设计经验谈:接口的设计 安全机制的设计 现在,大部分App的接口都采用RESTful架构,RESTFul最重要的一个设计原则就是,客户端与服务器的交互在请求之间是无状态的,也就是说,当涉及到用户状态时,每次请求都要带上身份验证信息。实现上,大部分都采用token的认证方式,一般流程是: 用户用密码登录成功后,服务器返回token给客户端; 客户端将token保存在本地,发起后续的相关请求时,将token发回给服务器; 服务器检查token的有效性,有效则返回数据,若无效,分两种情况: token错误,这时需要用户重新登录,获取正确的token token过期,这时客户端需要再发起一次认证请求,获取新的token 然而,此种验证方式存在一个安全性问题:当登录接口被劫持时,黑客就获取到了用户密码和token,后续则可以对该用户做任何事情了。用户只有修改密码才能夺回控制权。 如何优化呢?第一种解决方案是采用HTTPS。HTTPS在HTTP的基础上添加了SSL安全协议,自动对数据进行了压缩加密,在一定程序可以防止监听、防止劫持、防止重发,安全性可以提高很多。不过,SSL也不是绝对安全的,也存在被劫持的可能。另外,服务器对HTTPS的配置相对有点复杂,还需要到CA申请证书,而且一般还是收费的。而且,HTTPS效率也比较低。一般,只有安全要求比较高的系统才会采用HTTPS,比如银行。而大部分对安全要求没那么高的App还是采用HTTP的方式。 我们目前的做法是给每个接口都添加签名。给客户端分配一个密钥,每次请求接口时,将密钥和所有参数组合成源串,根据签名算法生成签名值,发送请求时将签名一起发送给服务器验证。类似的实现可参考OAuth1.0的签名算法。这样,黑客不知道密钥,不知道签名算法,就算拦截到登录接口,后续请求也无法成功操作。不过,因为签名算法比较麻烦,而且容易出错,只适合对内的接口。如果你们的接口属于开放的API,则不太适合这种签名认证的方式了,建议还是使用OAuth2.0的认证机制。 我们也给每个端分配一个appKey,比如Android、iOS、微信三端,每个端分别分配一个appKey和一个密钥。没有传appKey的请求将报错,传错了appKey的请求也将报错。这样,安全性方面又加多了一层防御,同时也方便对不同端做一些不同的处理策略。 另外,现在越来越多App取消了密码登录,而采用手机号+短信验证码的登录方式,我在当前的项目中也采用了这种登录方式。这种登录方式有几种好处: 不需要注册,不需要修改密码,也不需要因为忘记密码而重置密码的操作了; 用户不再需要记住密码了,也不怕密码泄露的问题了; 相对于密码登录其安全性明显提高了。 接口数据的设计 接口的数据一般都采用JSON格式进行传输,不过,需要注意的是,JSON的值只有六种数据类型: Number:整数或浮点数 String:字符串 Boolean:true 或 false Array:数组包含在方括号[]中 Object:对象包含在大括号{}中 Null:空类型 所以,传输的数据类型不能超过这六种数据类型。以前,我们曾经试过传输Date类型,它会转为类似于”2016年1月7日 09时17分42秒 GMT+08:00”这样的字符串,这在转换时会产生问题,不同的解析库解析方式可能不同,有的可能会转乱,有的可能直接异常了。要避免出错,必须做特殊处理,自己手动去做解析。为了根除这种问题,最好的解决方案是用毫秒数表示日期。 另外,以前的项目中还出现过字符串的”true”和”false”,或者字符串的数字,甚至还出现过字符串的”null”,导致解析错误,尤其是”null”,导致App奔溃,后来查了好久才查出来是该问题导致的。这都是因为服务端对数据没处理好,导致有些数据转为了字符串。所以,在客户端,也不能完全信任服务端传回的数据都是对的,需要对所有异常情况都做相应处理。 服务器返回的数据结构,一般为: {

code:0

message: "success"

data: { key1: value1, key2: value2, ... }} code: 状态码,0表示成功,非0表示各种不同的错误 message: 描述信息,成功时为”success”,错误时则是错误信息 data: 成功时返回的数据,类型为对象或数据 不同错误需要定义不同的状态码,属于客户端的错误和服务端的错误也要区分,比如1XX表示客户端的错误,2XX表示服务端的错误。这里举几个例子: 0:成功 100:请求错误 101:缺少appKey 102:缺少签名 103:缺少参数 200:服务器出错 201:服务不可用 202:服务器正在重启 错误信息一般有两种用途:一是客户端开发人员调试时看具体是什么错误;二是作为App错误提示直接展示给用户看。主要还是作为App错误提示,直接展示给用户看的。所以,大部分都是简短的提示信息。 data字段只在请求成功时才会有数据返回的。数据类型限定为对象或数组,当请求需要的数据为单个对象时则传回对象,当请求需要的数据是列表时,则为某个对象的数组。这里需要注意的就是,不要将data传入字符串或数字,即使请求需要的数据只有一个,比如token,那返回的data应该为: // 正确 data: { token: 123456 } // 错误 data: 123456 接口版本的设计 接口不可能一成不变,在不停迭代中,总会发生变化。接口的变化一般会有几种: 数据的变化,比如增加了旧版本不支持的数据类型 参数的变化,比如新增了参数 接口的废弃,不再使用该接口了 为了适应这些变化,必须得做接口版本的设计。实现上,一般有两种做法: 每个接口有各自的版本,一般为接口添加个version的参数。 整个接口系统有统一的版本,一般在URL中添加版本号,比如http://api.domain.com/v2。 大部分情况下会采用第一种方式,当某一个接口有变动时,在这个接口上叠加版本号,并兼容旧版本。App的新版本开发传参时则将传入新版本的version。 如果整个接口系统的根基都发生变动的话,比如微博API,从OAuth1.0升级到OAuth2.0,整个API都进行了升级。 有时候,一个接口的变动还会影响到其他接口,但做的时候不一定能发现。因此,最好还要有一套完善的测试机制保证每次接口变更都能测试到所有相关层面。 2.App架构设计经验谈:技术选型 当你做架构设计时,必然会面临技术选型的抉择,不同的技术方案,架构也可能完全不同。有哪些技术选型需要做决策呢?比如,App是纯原生开发,还是Web App,抑或Hybrid App?iOS开发,语言上是选择Objective-C还是Swift?架构模式用MVC,还是MVP,或者MVVM?下面根据我的一些经验对某些方面做点总结分享。 原生/H5 关于用原生好,还是用H5好的争论从没间断过。但我觉得,脱离了实际场景来讨论孰好孰坏意义不大。就说我们目前正在做的项目,先说明下背景: 不止要做Android和iOS App,也要做微信公众号; H5人员缺乏,只有一两个兼职的可用,而且不可控因素很高; 我们对原生比较熟; 开发时间只有半个月。 首先,需求上来说,大部分页面用H5实现,可以减少很多工作量。但因为不可控因素太高,而时间又短,风险太大。而我们对原生比较熟,开发效率比较高,很多东西我也控制得了,风险相对比较低。而且,我们的主推产品是App,微信属于辅助性产品,所以,微信要求也没那么高。因此,我决定以原生为主,H5为辅,App大部分页面用原

推荐:Hybrid APP架构设计思路

看到好文章,记录下:http://segmentfault.com/a/1190000004263182

生完成,小部分用WebView加载H5。 另外,WebView加载H5也有两种模式,一种是加载服务器的H5页面,一种是加载本地的H5页面。加载服务器的H5页面比较简单,WebView只要load一下URL就可以了。加载本地的H5页面,则需要将H5文件存放在本地,包括关联的CSS和JS文件。这种方式相对比较复杂,不过,加载速度会比第一种快很多。我们当前项目基于上面考虑,只能选择第一种方案。 如果人员和时间资源充足的话,那又如何选型呢?毫无疑问,我会以H5为主,微信和App都有的页面统一用H5,App专有的部分,比如导航栏、标题栏、登录等,才用原生实现。另外,WebView里的H5有点击事件时,也许是URL链接,也许是调用JS的,都不会让它直接在该WebView里做跳转,需要拦截下来做些原生处理后跳转到一个新的原生页面,原生页面也许嵌入另一个WebView,用来展示新的H5页面。这是简单的例子,关于Hybrid App详细的设计,以后再讲。另外,关于H5,绝对是大趋势,强烈建议所有App开发人员都去学习。 Objective-C/Swift 我在项目中选择了Swift,主要基于三个原因: Swift真的很简洁,生产效率很高; Swift取代Objective-C是必然的趋势; 目前iOS只有我一个人开发,不需要顾虑到团队里没人懂Swift。 如果你的团队里没人懂Swift,那还是乖乖用Objective-C吧;如果有一两个懂Swift的,那可以混合开发,并让不懂的人尽快学会Swift;如果都懂了,不用想了,直接上Swift吧。 当语言上选择了Swift,相应的一些第三方库也面临着选型。比如,依赖库管理,Objective-C时代大部分用CocoaPods,Swift时代,我更喜欢Carthage。Carhage是用Swift写的,和CocoaPods相比,轻耦合,也更灵活。我个人也不太喜欢CocoaPods,使用起来比较麻烦,耦合性也较高,我使用过程中也经常出问题,而且还总是不知道该怎么解决,要移除时也是非常麻烦。 再推荐几个关于Swift的第三方库: Alamofire:Swift版本的网络基础库,和AFNetworking是同一个作者 AlamofireImage:基于Alamofire的图片加载库 ObjectMapper:Swift版本的Json和Model转换库 AlamofireObjectMapper:Alamofire的扩展库,结合了ObjectMapper,自动将JSON的Response数据转换为了Swift对象 MVC/MVP/MVVM 先分别简单介绍下这三个架构模式吧: MVC:Model-View-Controller,经典模式,很容易理解,主要缺点有两个: View对Model的依赖,会导致View也包含了业务逻辑; Controller会变得很厚很复杂。 MVP:Model-View-Presenter,MVC的一个演变模式,将Controller换成了Presenter,主要为了解决上述第一个缺点,将View和Model解耦,不过第二个缺点依然没有解决。 MVVM:Model-View-ViewModel,是对MVP的一个优化模式,采用了双向绑定:View的变动,自动反映在ViewModel,反之亦然。 架构模式上,我不会推崇说哪种模式好,每种模式都各有优点,也各有极限性。越高级的模式复杂性越高,实现起来也越难。最近火热的微服务架构,比起MVC,复杂度不知增加了多少倍。 我在实际项目中思考架构时,也不会想着要用哪种模式,我只思考现阶段,以现有的人力资源和时间资源,如何才能更快更好地完成需求,适当考虑下如何为后期扩展或重构做准备。就说我前段时间分享的Android项目重构之路系列中讲的那个架构,确切地说,都不属于上面三种架构模式之一。 3.App架构设计经验谈:数据层的设计 一个App,从根本上来说,就是对数据的处理,包括数据从哪里来、数据如何组织、数据怎么展示,从职责上划分就是:数据管理、数据加工、数据展示。相对应的也就有了三层架构:数据层、业务层、展示层。本文就先讲讲数据层的设计。 数据层,是三层架构中的最底层,负责数据的管理。它主要的任务就是: 调用网络API,获取数据; 将数据缓存到本地; 将数据交付给上一层。 根据这三个任务,数据层可以再拆分为三层:网络层、本地数据层、交付层。 网络层 网络层主要就是对网络API的封装。关于API的设计,该系列的第一篇文章接口的设计已经讲过一些。关于如何封装,可以参考Android项目重构之路系列的架构篇和实现篇,其中接口层和本文的网络层是一样的。 还有一些在前面的文章中没有提及到的,在此做一些补充。 首先是不同网络状态的处理。当网络不可用时,则不应该再去调用API;当网络可用,但不是WIFI时,有些比较耗流量的操作也应该禁止,比如上传和下载大文件;当网络状态不同时,还可以采用不同的网络策略,比如,当网络为WIFI时,当前API可以返回更多更全面的数据,还可以预先加载相关联的其他API。 其次,为了节省流量,接口的设计上可以对数据进行简化。例如,对于一些列表类的接口,可以这么设计:只返回更新的部分,比如,上一次请求返回了10条按时间排序的数据,第一条数据为最新的,id为101,当发起下一次请求时,将101的id作为参数调用API,API查到该id,发现该id之后又新增了两条数据,API则只返回新增的这两条数据。 另外,为了保证程序的健壮性,调用API时,对入参的合法性检查也是很有必要的。而且,也应该定义好本地的错误码和错误信息,保证每个错误都能正常解析。 本地数据层 本地数据层主要就是做缓存处理,这需要设计好一套缓存策略。设计缓存策略时,有几个问题需要考虑清楚: 哪些需要缓存?哪些不需要缓存? 缓存在哪里?数据库?文件?还是内存? 缓存时间多长? 哪些需要缓存? 将所有数据都缓存是不明智的,不同的数据应该有不同的缓存策略,比如一个电商App,首页的商品列表数据应该缓存,而且缓存时间应该比较长,而每个商品的详情数据就没必要缓存或缓存时间很短。对于一份数据需不需要缓存,判断标准可以是:用户查看该数据的频率高不高?首页商品列表是用户每次启动都会看到的,而每个商品的详情用户最多只看几次。 缓存在哪里? 从内存读取数据是最快的,但内存非常有限。因此,内存一般只用来缓存使用频率非常高的数据。 文件缓存主要就是图片、音频、视频了。 数据库可以保存大量数据,主要就是用于保存商品列表、聊天记录之类的关系型数据。 然而,不管缓存在哪里,都需要限定好缓存的容量,要定期清理,不然会越积越多。 缓存时间多长? 首先,每份缓存数据都应该设置一个缓存的有效时间,有效期的起始时间以最后一次被调用的时间为准,当该数据长时间没有再被调用到时,就应该从缓存中清理掉。 缓存的有效时间应该设多长呢?可以短至一分钟,长至一星期甚至一个月,具体因数据而异。一般内存的缓存时间不宜太长,程序退出基本就要全部清理了。文件缓存可以设置保留一天或一个星期,可以每隔一天清理一次。数据库缓存再久一些也无所谓,但最好还是不要超过一个月。 交付层 交付层其实就是一个向上层开放的交互接口层,是上层向数据层获取数据的入口。上层向数据层请求数据,它是不关心数据层的数据是从缓存获取还是从网络获取的,它只关心结果,数据层能给到它想要的数据结果就OK了。因此,交付层主要就是定义一堆开放的接口或协议。 如果接口或协议非常多,那么,将接口或协议按照模块划分也是有必要的。比如微信,按模块划分有:IM、公众号、朋友圈、钱包、购物、游戏等等。模块之间应该尽量相对独立、松耦合。

推荐:web架构设计经验分享

本人作为一位web工程师,着眼最多之处莫过于 性能与架构,本次幸得参与sd2.0大会,得以与同行广泛交流,于此二方面,有些心得,不敢独享,与众博友分享,本文是这

转载自Keegan小钢 1.App架构设计经验谈:接口的设计 安全机制的设计 现在,大部分App的接口都采用RESTful架构,RESTFul最重要的一个设计原则就是,客户端与服务器的交互在请求之间是无状态的,也

相关阅读排行


用户评论

游客

相关内容推荐

最新文章

×

×

请激活账号

为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。

您的注册邮箱: 修改

重新发送激活邮件 进入我的邮箱

如果您没有收到激活邮件,请注意检查垃圾箱。