本文主要是介绍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管理器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!