对于客户端应用程序,免不了和远程服务打交道。设计一个良好的『服务层』能帮我们规范和分离业务代码,提高生产效率。服务层最核心的模块一定是怎样发送请求,虽然Mono提供了很多C#网络请求类,诸如WebClientHttpWebRequest,但考虑到跨平台,这些类不一定适用。不过不用担心,Unity 5.x提供了新的与网络相关类UnityWebRequest用来替代原先的WWW,这是官方推荐的,也是最佳选择。

使用Token进行身份验证

首先我们必须要考虑的是,怎样和Web服务安全的通信。没错,肯定是身份验证(Authentication)。对于像WebClient这些类,它们会提供一个属性,比如Credentials,可以在此属性设置一些身份验证信息,比如用户名,密码,域。这是一个很『重』的解决方案,且不论是否能在Unity中实现,单从密码这个角度,很多游戏根本不需要密码。所以,我们需要一种『轻』量级的身份验证机制,这就是Token,中文翻译叫『令牌』。

Token有两个重要的特点:

  • 代表了唯一的身份验证令牌
  • 具有时效性

第一点我们肯定可以理解,唯一性是身份验证的的基础。那第二点怎么理解呢?其实,Token本质上是一串加密过后的字符串,如果没有时效性,万一被窃取之后,他人很容易进行伪造。所以,易变的Token一定比不变的安全,你需要一个算法来动态生成Token,我提供一个简单的算法:

md5(((day*10) + (month*100) + (last2DigitsofYear)*1000)+userId+deviceId)

同理,你需要在Web服务前加上一个过滤器,一样的算法来验证Token是否一致。

Request Pipeline

Pipeline是管道的意思,管道是相连的,代表了请求的流转。由于UnityWebRequest必须配合StartCoroutine,而StartCoroutine又属于View层的代码,这和分层(详见之前的文章)冲突,MVVM框架需要将业务逻辑从View解耦。一个比较好的解决方案是通过中介的HttpTool来解决,它是一个单例的MonoBehaviour,并且不会随着场景的加载被销毁。

public class HttpTool : Singleton<HttpTool>
{// 无法在外界使用构造函数,确保Singletonprotected HttpTool() { }
}

不管是请求还是响应,本质上是一堆数据的集合,将这些数据封装成对象的形式会更加容易管理,我将请求相关的数据封装成HttpRequest对象:

public class HttpRequest
{public string Url { get; set; }public HttpMethod Method { get; set; }public string Parameters { get; set; }
}

而将从Web服务返回的数据封装成HttpResponse对象:

public class HttpResponse
{public bool IsSuccess { get; set; }public string Error { get; set; }public long StatusCode { get; set; }public string Data { get; set; }
}

值得注意的是,对应Http请求,不论Get还是Post都会将参数组装成“field1=value1&field2=value2”格式,不同的是Get请求,参数会跟在Url后,而Post请求则在Request Body里。所以需要一个帮助类,反射要传递的对象属性,拼装返回字符串。

核心的请求交由UnityWebRequest实现,通过yield等待返回的结果:

using (var www = UnityWebRequest.Get(url + parameters))
{yield return www.Send();var response = new HttpResponse{IsSuccess = !www.isError, Error = www.error, StatusCode = www.responseCode, Data = www.downloadHandler.text};onComplete(response);
}

最后再对返回的Json字符串反序列化成对象,值得注意的是,在此我用了内置的JsonUtility类,它并不能直接反序列化一个Json数组 ,而是需要将它包装成一个对象 ,通过集合类型属性的形式间接被反序列化。

至此,一个完整的Request Pipeline 如下图所示:

使用策略模式增强RemoteRepository

由于JsonUtility的限制因素多,你可能使用其他第三方的库。又或者不反序列化Json,而是Xml。所以在RemoteRepository中不应该限制死反序列化的代码,更好的想法是通过『策略模式』,交由外部算法来实现。这样的好处是你根本不需要改动RemoteRepository里的代码,这也符合『开闭原则』。

所以,你需要在RemoteRepository定义一个序列化接口:

public ISerializer Serializer { get; set; }

然后,对返回的HttpResponse中的Json反序列化:

Serializer.Deserialize<R>(httpResponse.Data)

真正的对Json序列化器实现了ISerializer接口,以策略的形式存在:

public class SerializerJson:ISerializer
{public static readonly SerializerJson Instance=new SerializerJson();private SerializerJson(){}public string Serialize<T>(T obj, bool readableOutput = false) where T : class, new(){throw new NotImplementedException();}public T Deserialize<T>(string json) where T : class, new(){return JsonUtility.FromJson<T>(json);}
}

策略模式在编程领域运用非常广,比如Java或者.NET框架里的集合排序,大量用到策略模式。由程序员指定的算法来最终实现排序。

小结

本文的核心思想就是如何在合理分层结果下构建一个好用的服务层。谈到了如何动态生成Token来实现身份验证,以及分层情况下的请求流程。对于2D并且以数据绑定为基础的游戏,我认为这是一个好的实践方案。因为不管是三层架构还是N层架构,通过分层的好处是更加清晰去实现业务逻辑。
源代码托管在Github上,点击此了解

Unity应用架构设计(11)——一个网络层的构建相关推荐

  1. 视频教程-Unity网络游戏架构设计-Unity3D

    Unity网络游戏架构设计 网名:海洋,CSDN社区讲师,3D游戏引擎开发者,IT讲师,计算机图形学方向研究生,曾在浙江大学CAD&CG;国家重点实验室学习.从事IT行业15年,主导或参与了1 ...

  2. Unity应用架构设计(10)——绕不开的协程和多线程(Part 1)

    阅读目录 是否需要多线程? 协程的内部原理 小结 在进入本章主题之前,我们必须要了解客户端应用程序都是单线程模型,即只有一个主线程(Main Thread),或者叫做UI线程,即所有的UI控件的创建和 ...

  3. 前端架构设计第六课工程化构建、编译、运行

    12 如何理解 AST 实现和编译原理? 经常留意前端开发技术的同学一定对 AST 技术不陌生.AST 技术是现代化前端基建和工程化建设的基石:Babel.Webpack.ESLint.代码压缩工具等 ...

  4. 简单Unity时间架构设计(克洛诺斯之匙)

    好吧,这次的题目有点标题党之嫌,提出这个设计,是因为最近玩了鬼泣,其中有一个关卡叫做"为了自己的主人",任务中,需要利用克洛诺斯之匙将时间变慢,便于通过激光镇. 使用克洛诺斯之匙之 ...

  5. 自学架构设计的一个好方法

    架构设计,讲起来,比较虚,不像算法和代码.你写了一段巧妙的代码,编译,运行,如果最终结果是正确的,那就是正确的. 但架构设计就不同了,你就算自己脑子YY了一个架构出来,好不好,有时候自己还真不好判断, ...

  6. Unity应用架构设计(1)—— MVVM 模式的设计和实施(Part 2)

    MVVM回顾 经过上一篇文章的介绍,相信你对MVVM的设计思想有所了解.MVVM的核心思想就是解耦,View与ViewModel应该感受不到彼此的存在. View只关心怎样渲染,而ViewModel只 ...

  7. Unity应用架构设计(9)——构建统一的 Repository

    谈到 『Repository』 仓储模式,第一映像就是封装了对数据的访问和持久化.Repository 模式的理念核心是定义了一个规范,即接口『Interface』,在这个规范里面定义了访问以及持久化 ...

  8. Unity应用架构设计(6)——设计动态数据集合ObservableList

    什么是 『动态数据集合』 ?简而言之,就是当集合添加.删除项目或者重置时,能提供一种通知机制,告诉UI动态更新界面.有经验的程序员脑海里迸出的第一个词就是 ObservableCollection.没 ...

  9. Unity应用架构设计(7)——IoC工厂理念先行

    一谈到 『IoC』,有经验的程序员马上会联想到控制反转,将创建对象的责任反转给工厂.IoC是依赖注入 『DI』 的核心,大名鼎鼎的Spring框架就是一个非常卓越的的控制反转.依赖注入框架.遗憾的是, ...

最新文章

  1. python测试开发django-8.windows系统安装mysql8教程
  2. 分享Silverlight/WPF/Windows Phone一周学习导读(1月9日-1月16日)
  3. html5 原生 弹窗,HTML5 Popmotion.js实现的弹窗控件
  4. HOOK大法实现不修改程序代码给程序添加功能
  5. 随机数是骗人的,.Net、Java、C为我作证 - 杨中科 - 博客园
  6. 多级队列调度算法可视化界面_多级反馈队列调度算法
  7. C#项目中的bin目录和obj目录的区别,以及Debug版本和Release版本的区别(转载)...
  8. 爬虫练习:南阳理工学院ACM题目信息
  9. ENVI软件App Store插件工具的下载、安装与使用方法
  10. 高德地图报Native method not found: com.autonavi.amap.mapcore.MapCore.nativeNewInstance:
  11. 【基础理论】Jenkins CI/DI持续集成部署
  12. 如何查看电脑操作系统及系统类型
  13. centernet代码阅读笔记
  14. 一款APP从设计稿到切图过程全方位揭秘
  15. 华为南研所2015年面试经历总结
  16. Sqlite出现database is locked
  17. Java中的经典算法之冒泡排序(Bubble Sort)
  18. 春节灯笼Html代码实现+点击页面出现文字
  19. Aeon项目今天正式启动
  20. 超级文本编辑器Sublime Text3

热门文章

  1. 学习嵌入式系统需要具备的条件、方法及步骤
  2. PHP SOAP 扩展的使用
  3. JavaScript之function类型
  4. EDM营销中HTML邮件设计方法和技巧
  5. 反弹和补遗:再论Bjarne Stroustrup的基于对象的含义
  6. 大型软件公司.net面试题!一定得看(附答案)
  7. python3.X 使用schedule实现定时任务
  8. dart参数传方法_为 JavaScript 开发人员准备的 Dart 参考教程
  9. 8.0强行转换后变成了7_【自学C#】|| 笔记 12 数据类型转换
  10. 命令注入工具Commix