U3D客户端框架之实现基于UnityWebRequest的Http服务 实现HttpCallBackArgs参数类、HttpRoutine访问器、HttpManager管理器

本文主要是介绍U3D客户端框架之实现基于UnityWebRequest的Http服务 实现HttpCallBackArgs参数类、HttpRoutine访问器、HttpManager管理器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 Http服务 访问器设计思路

        Unity3D 在2018版本中弃用了WWW请求,使用UnityWebRequest 进行网络请求,这个方法是为了满足今天的 HTTP 通信的需求,而且诞生的新类,相对于WWW这个方法,会更灵活一些,但是用起来却很不方便。

        所以我将UnityWebRequest封装了一下。封装的目的有两个:1.封装后访问Http用着方便;2.在框架层上隔离原生API和具体业务,即使后续API变更也不会影响到业务逻辑,避免业务受影响。

2 代码实现

Get和Post的区别可以看 引用模块中 Get和Post对比的链接,那篇文章中详细讲解了Get和Post的异同和使用场景。

HttpCallBackArgs:Http请求的回调数据,包装了是否有错、返回值、数据Bytes数组;说明一下HttpCallBackArgs继承EventArgs,是为了准守规范,让看代码的人一看到这个类型,就知道这是一个事件类型,使用的时候直接吧EventArgs转换成具体的事件参数类即可。

HttpCallBackArgs.cs 代码实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Myh
{//http请求的回调数据public class HttpCallBackArgs : EventArgs{//是否有错(是否发生了错误)public bool HasError;//返回值 public string Value;//字节数据 public byte[] Data;}
}

HttpRoutine:Http访问Url的轮询器,核心代码的所在文件;内部实现了GetUrl、PostUrl,状态监测、回调处理、对失败情况下的重试逻辑

HttpRoutine.cs 代码实现

using LitJson;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using YouYou;namespace Myh
{//Http发送数据的回调委托 public delegate void HttpSendDataCallBack(HttpCallBackArgs args);//Http访问器public class HttpRoutine{//Http请求回调private HttpSendDataCallBack m_CallBack;//Http请求回调数据private HttpCallBackArgs m_CallBackArgs;//是否繁忙public bool IsBusy{get;private set;}//当前重试次数(尝试重新访问次数?)public int m_CurrRetry = 0;//URLprivate string m_Url;//是否是Getprivate bool m_IsGetData = false;//是否是Postprivate bool m_IsPost = false;//发送的数据private Dictionary<string, object> m_Dic;public HttpRoutine(){m_CallBackArgs = new HttpCallBackArgs();}#region SendData 发送Web数据public void SendData(string url, HttpSendDataCallBack cb, bool isPost = false,bool isGetData = false, Dictionary<string, object> dic = null){if (IsBusy)return;m_Url = url;m_CallBack = cb;m_IsPost = isPost;m_IsGetData = isGetData;m_Dic = dic;SendData();}private void SendData(){//不是post模式if (!m_IsPost){GetUrl(m_Url);}else{//把数据存到字典里if (m_Dic != null){//设备唯一Idm_Dic["deviceIdentifier"] = DeviceUtil.DeviceIdentifier;//设备型号m_Dic["deviceModel"] = DeviceUtil.DeviceModel;//服务器时间 TODO://还没有和服务器同步时间,暂时先用本地时间long t = DateTime.Now.Ticks;//用当前服务器时间 和 设备id 算一个md5出来 作为本地请求的签名(签名具有时效性,超时无效)string md5 = string.Format("{0}:{1}",t,DeviceUtil.DeviceIdentifier);m_Dic["sign"] = EncryptUtil.Md5(md5);//时间戳m_Dic["t"] = t;}string json = string.Empty;if (m_Dic != null){json = JsonMapper.ToJson(m_Dic);//不是get的方式if (!m_IsGetData){
#if DEBUG_LOG_PROTO && DEBUG_MODELGameEntry.Log(LogCategory.Proto, "<color=#ffa200>发送消息:</color><color=#FFFB80>" + m_Url + "</color>");GameEntry.Log(LogCategory.Proto, "<color=#ffdeb3>==>>" + json + "</color>");
#endif }GameEntry.Pool.EnqueueClassObject(m_Dic);}PostUrl(m_Url,json);}}#endregion#region GetUrl Get请求//Get请求private void GetUrl(string url){UnityWebRequest request = UnityWebRequest.Get(url);YouYou.GameEntry.Instance.StartCoroutine(Request(request));}#endregion#region PostUrl Post请求//Post请求private void PostUrl(string url, string json){//定义一个表单WWWForm form = new WWWForm();//给表单添加值form.AddField("json",json);//把url 和表单传入进去UnityWebRequest request = UnityWebRequest.Post(url,form);GameEntry.Instance.StartCoroutine(Request(request));}#endregion#region Request 请求服务器/** 功能:请求Web服务器* request:UnityWebRequest请求的实体*/private IEnumerator Request(UnityWebRequest request){//阻塞方法  和目标服务器建立连接,返回结果后才继续下一步yield return request.SendWebRequest();//如果有错误,重试与目标服务器连接(通信)if (request.isNetworkError || request.isHttpError){//报错了进行重试if (m_CurrRetry > 0){//过一段时间后再重新判断yield return new WaitForSeconds(GameEntry.Http.RetryInterval);}//重试次数+1++m_CurrRetry;//如果<=配置的重试次数if (m_CurrRetry <= GameEntry.Http.Retry){
#if DEBUG_LOG_PROTO && DEBUG_MODEL//通过宏开关,决定要不要打印logGameEntry.Log(LogCategory.Proto, "<color=#00eaff>请求URL:</color> <color=#00ff9c>{0}失败 当前重试次数{1}</color>", m_Url, m_CurrRetry);
#endif//调用SendData,重新发送数据SendData();//结束本次携程yield break;}//超过次数了,状态设置成有错误IsBusy = false;if (null != m_CallBack){m_CallBackArgs.HasError = true;m_CallBackArgs.Value = request.error;//不是GetData 方式的话 打印一个logif (!m_IsGetData){
#if DEBUG_LOG_PROTO && DEBUG_MODELGameEntry.Log(LogCategory.Proto, "<color=#00eaff>接收消息:</color> <color=#00ff9c>" + request.url + "</color>");GameEntry.Log(LogCategory.Proto, "<color=#c5e1dc>==>>" + JsonUtility.ToJson(m_CallBackArgs) + "</color>");
#endif}m_CallBack(m_CallBackArgs);}}//与主机建立连接else{IsBusy = false;if(null!=m_CallBack){m_CallBackArgs.HasError = false;m_CallBackArgs.Value = request.downloadHandler.text;if (!m_IsGetData){
#if DEBUG_LOG_PROTO && DEBUG_MODELGameEntry.Log(LogCategory.Proto, "<color=#00eaff>接收消息:</color> <color=#00ff9c>" + request.url + "</color>");GameEntry.Log(LogCategory.Proto, "<color=#c5e1dc>==>>" + JsonUtility.ToJson(m_CallBackArgs) + "</color>");
#endif}m_CallBackArgs.Data = request.downloadHandler.data;m_CallBack(m_CallBackArgs);}}//重试完毕,或者下载完毕m_CurrRetry = 0;m_Url = null;if (null != m_Dic){m_Dic.Clear();m_Dic = null;}m_CallBackArgs.Data = null;request.Dispose();request = null;//把Http访问器回池GameEntry.Pool.EnqueueClassObject(this);}#endregion}
}

HttpManager:Http服务器的管理类,记录了账号服务器的Url,通过HttpManager开启HttpRoutine。

HttpManager.cs 代码实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Myh
{public class HttpManager : ManagerBase, IDisposable{//正式服 账号服务器urlprivate string m_WebAccountUrl;//测试服 账号服务器urlprivate string m_TestWebAccountUrl;//是否是测试环境private bool m_IsTest;//真实账号服务器Urlpublic string RealWebAccountUrl{get{return m_IsTest ? m_TestWebAccountUrl : m_WebAccountUrl;}}//连接失败后重试次数public int Retry{get;private set;}//连接失败后重试间隔(单位:秒)public float RetryInterval{get;private set;}public override void Init(){//TODO:这些应该都要从设置里读取,可是现在没有,到时候回来改m_WebAccountUrl = "";m_TestWebAccountUrl = "";m_IsTest = true;Retry = 5;RetryInterval = 2f;}public void SendData(string url, HttpSendDataCallBack cb, bool isPost = false, bool isGetData = false, Dictionary<string, object> dic = null){//从类对象池里,获取http访问器HttpRoutine httpRoutine = YouYou.GameEntry.Pool.DequeueClassObject<HttpRoutine>();httpRoutine.SendData(url, cb, isPost, isGetData, dic);}public void Dispose(){}}
}

3 代码测试

Get访问网页会把网页内的Html代码读出来;Getzip会把zip下载下来。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Myh;
using YouYou;
using UnityEngine;public class TestHttp : ITest
{private void TestGetWebUrl(){GameEntry.Http.SendData("https://www.baidu.com", (HttpCallBackArgs args) =>{GameEntry.Log(LogCategory.Normal, "httpCallbackArgs hasError:{0} Value:{1} data str:{2}",args.HasError, args.Value, Encoding.UTF8.GetString(args.Data));});}private void TestGetDownloadUrl(){//从web站点上下载eee.zip文件GameEntry.Http.SendData("https://www.xxx.com/s/eee.zip", (HttpCallBackArgs args) =>{GameEntry.Log(LogCategory.Normal, "httpCallbackArgs hasError:{0} Value:{1} data str:{2}",args.HasError, args.Value, Encoding.UTF8.GetString(args.Data));});}public void OnTestStart(){}public void OnTestUpdate(){if (Input.GetKeyDown(KeyCode.Q)){TestGetWebUrl();}else if (Input.GetKeyDown(KeyCode.E)){TestGetDownloadUrl();}}
}


4 引用

Get和Post对比:HTTP请求中Get和Post的区别是什么?_天才小熊猫oo的博客-CSDN博客

这篇关于U3D客户端框架之实现基于UnityWebRequest的Http服务 实现HttpCallBackArgs参数类、HttpRoutine访问器、HttpManager管理器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/452881

相关文章

Python中edge-tts实现便捷语音合成

《Python中edge-tts实现便捷语音合成》edge-tts是一个功能强大的Python库,支持多种语言和声音选项,本文主要介绍了Python中edge-tts实现便捷语音合成,具有一定的参考价... 目录安装与环境设置文本转语音查找音色更改语音参数生成音频与字幕总结edge-tts 是一个功能强大的

Java实现按字节长度截取字符串

《Java实现按字节长度截取字符串》在Java中,由于字符串可能包含多字节字符,直接按字节长度截取可能会导致乱码或截取不准确的问题,下面我们就来看看几种按字节长度截取字符串的方法吧... 目录方法一:使用String的getBytes方法方法二:指定字符编码处理方法三:更精确的字符编码处理使用示例注意事项方

使用Python和PaddleOCR实现图文识别的代码和步骤

《使用Python和PaddleOCR实现图文识别的代码和步骤》在当今数字化时代,图文识别技术的应用越来越广泛,如文档数字化、信息提取等,PaddleOCR是百度开源的一款强大的OCR工具包,它集成了... 目录一、引言二、环境准备2.1 安装 python2.2 安装 PaddlePaddle2.3 安装

嵌入式Linux之使用设备树驱动GPIO的实现方式

《嵌入式Linux之使用设备树驱动GPIO的实现方式》:本文主要介绍嵌入式Linux之使用设备树驱动GPIO的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、设备树配置1.1 添加 pinctrl 节点1.2 添加 LED 设备节点二、编写驱动程序2.1

Android 实现一个隐私弹窗功能

《Android实现一个隐私弹窗功能》:本文主要介绍Android实现一个隐私弹窗功能,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 效果图如下:1. 设置同意、退出、点击用户协议、点击隐私协议的函数参数2. 《用户协议》、《隐私政策》设置成可点击的,且颜色要区分出来res/l

spring IOC的理解之原理和实现过程

《springIOC的理解之原理和实现过程》:本文主要介绍springIOC的理解之原理和实现过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、IoC 核心概念二、核心原理1. 容器架构2. 核心组件3. 工作流程三、关键实现机制1. Bean生命周期2.

史上最全nginx详细参数配置

《史上最全nginx详细参数配置》Nginx是一个轻量级高性能的HTTP和反向代理服务器,同时也是一个通用代理服务器(TCP/UDP/IMAP/POP3/SMTP),最初由俄罗斯人IgorSyso... 目录基本命令默认配置搭建站点根据文件类型设置过期时间禁止文件缓存防盗链静态文件压缩指定定错误页面跨域问题

Redis实现分布式锁全解析之从原理到实践过程

《Redis实现分布式锁全解析之从原理到实践过程》:本文主要介绍Redis实现分布式锁全解析之从原理到实践过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、背景介绍二、解决方案(一)使用 SETNX 命令(二)设置锁的过期时间(三)解决锁的误删问题(四)Re

Java根据IP地址实现归属地获取

《Java根据IP地址实现归属地获取》Ip2region是一个离线IP地址定位库和IP定位数据管理框架,这篇文章主要为大家详细介绍了Java如何使用Ip2region实现根据IP地址获取归属地,感兴趣... 目录一、使用Ip2region离线获取1、Ip2region简介2、导包3、下编程载xdb文件4、J

PyQt5+Python-docx实现一键生成测试报告

《PyQt5+Python-docx实现一键生成测试报告》作为一名测试工程师,你是否经历过手动填写测试报告的痛苦,本文将用Python的PyQt5和python-docx库,打造一款测试报告一键生成工... 目录引言工具功能亮点工具设计思路1. 界面设计:PyQt5实现数据输入2. 文档生成:python-