以前项目的网络请求一直是在用BestHttp插件来进行处理的,由于插件的某些不可控性以及为了不过分依赖插件,所以在这次项目重构的过程中准备换成Unity自己封装的请求方式进行处理,不得不说现在的UnityWebRequest比老版本的WWW要好用多了,下面会介绍这个请求的管理模式。
首先我把每一个请求都抽象成为一个请求对象(RequestNet),包含Get、Post请求,再由一个请求管理类(RequestManager)来管理这些对象,下表我会把请求对象和请求管理类的公共方法给列举出来
RequestNet
方法 |
描述 |
RequestNet(string _requestUrl) |
【构造函数】参数1(请求链接) |
SetRequestUrl(string _url) |
【重新设置url】 参数1(请求链接) |
SetTimeout(int value) |
【设置请求超时时间】 参数1(超时时间,单位:秒) |
Send(NetMethod _method, Dictionary<string, string> _paramsDict) |
【发送请求】 参数1(请求方式:Get、Post) 参数2(请求参数键值对) |
PostUpload(Dictionary<string,string> _paramsDict,BinaryData _binaryData) |
【Post方式上传文件】 参数1(请求参数键值对),参数2(文件对象BinaryData) |
OnComplete(Action<bool, string, int> _completeAct) |
【注册请求结束回调】 参数1(回调委托(是否请求成功,请求返回信息,http返回的code码)) |
Close(bool isDestroy=false) |
【关闭请求对象】 参数1(是否销毁,如果为true则不入对象池) |
RequestManager
方法 |
描述 |
Send(string _url, NetMethod _method, Dictionary<string, string> _paramsDict) |
【发送请求】 参数1(url),参数2(请求方式),参数3(请求参数键值对) |
PostUpload(string _url, Dictionary<string, string> _paramsDict,BinaryData binaryData) |
【Post请求并上传数据流】 参数1(url),参数2(请求参数键值对),参数3(文件信息) |
PostUploads(string _url, Dictionary<string, string> _paramsDict,List binaryDataList,Action _progressAct,Action<bool,List> _completeAct) |
【Post模式上传多个文件信息】 参数1(url),参数2(参数键值对),参数3(文件信息列表),参数4(上传进度回调 int值为已经成功上传的个数),参数5(上传结束回调,bool 代表是否全部上传成功,List为所有上传失败文件的索引) |
源码
using System;
using System.Collections;
using System.Collections.Generic;
using AR_Net_Request;
using UnityEngine;
using UnityEngine.Networking;
namespace AR_Net_Request
{
/// <summary>
/// 请求方式
/// </summary>
public enum NetMethod
{
POST,
GET
}
/// <summary>
/// 上传信息管理
/// </summary>
public struct BinaryData
{
/// <summary>
/// 字段名
/// </summary>
public string fieldName;
/// <summary>
/// 需要上传的数据流
/// </summary>
public byte[] byteInfoArr;
/// <summary>
/// 文件名
/// </summary>
public string fileName;
public string mimeType;
public BinaryData(string _fieldName,byte[] _byteInfoArr,string _fileName=null,string _mimeType=null)
{
fieldName = _fieldName;
byteInfoArr = _byteInfoArr;
fileName = _fileName;
mimeType = _mimeType;
}
}
/// <summary>
/// 网络请求管理器
/// </summary>
public class RequestManager : MonoBehaviour
{
private static RequestManager _instance;
public static RequestManager instance
{
get
{
if (_instance == null)
{
_instance = GameObject.FindObjectOfType<RequestManager>();
if (_instance == null)
{
GameObject obj = new GameObject("RequestManager");
_instance = obj.AddComponent<RequestManager>();
DontDestroyOnLoad(obj);
}
}
return _instance;
}
}
//公用的请求头参数
private static Dictionary<string, string> headParamsDict;
/// <summary>
/// 闲置的请求池
/// </summary>
private static List<RequestNet> requestPool = new List<RequestNet>();
/// <summary>
/// 请求池容量
/// </summary>
public static int poolCount = 10;
private void Awake()
{
InitHeadParamsDict();
}
/// <summary>
/// 请求
/// </summary>
/// <param name="_url">url</param>
/// <param name="_method">请求方式</param>
/// <param name="_paramsDict">请求参数</param>
/// <returns></returns>
public RequestNet Send(string _url, NetMethod _method, Dictionary<string, string> _paramsDict)
{
RequestNet net = GetRequestNet(_url);
net.Send(_method, _paramsDict);
return net;
}
/// <summary>
/// Post请求并上传数据流
/// </summary>
/// <param name="_url"></param>
/// <param name="_paramsDict">参数</param>
/// <param name="binaryData">数据流信息</param>
/// <returns></returns>
public RequestNet PostUpload(string _url, Dictionary<string, string> _paramsDict,BinaryData binaryData)
{
RequestNet net = GetRequestNet(_url);
net.PostUpload(_paramsDict,binaryData);
return net;
}
/// <summary>
/// Post模式上传多个文件信息
/// </summary>
/// <param name="_url">url</param>
/// <param name="_paramsDict">参数字典</param>
/// <param name="binaryDataList">所有文件的byte信息列表</param>
/// <param name="_progressAct">上传进度回调 int值为已经成功上传的个数</param>
/// <param name="_completeAct">上传结束回调,bool 代表是否全部上传成功,List为所有上传失败文件的索引</param>
public void PostUploads(string _url, Dictionary<string, string> _paramsDict,List<BinaryData> binaryDataList,Action<int> _progressAct,Action<bool,List<int>> _completeAct)
{
StartCoroutine(PostUploadsIE(_url, _paramsDict, binaryDataList,_progressAct, _completeAct));
}
IEnumerator PostUploadsIE(string _url,Dictionary<string, string> _paramsDict,List<BinaryData> binaryDataList,Action<int> _progressAct,Action<bool,List<int>> _completeAct)
{
int successCount = 0;
List<int> errorList = new List<int>();
for (int i = 0; i < binaryDataList.Count; i++)
{
bool isContinue = false;
int id = i;
PostUpload(_url, _paramsDict, binaryDataList[i]).OnComplete((bool isSuccess, string responseStr,
int httpCode) =>
{
isContinue = true;
if (!isSuccess)
{
errorList.Add(id);
}
else
{
successCount++;
_progressAct?.Invoke(successCount);
}
});
Func<bool> act = delegate() { return isContinue; };
yield return new WaitUntil(act);
}
_completeAct?.Invoke(errorList.Count == 0,errorList);
}
/// <summary>
/// 得到一个RequestNet新的请求对象
/// </summary>
/// <param name="_url">url</param>
/// <returns></returns>
private RequestNet GetRequestNet(string _url)
{
RequestNet net = null;
if (requestPool!=null&&requestPool.Count>0)
{
net = requestPool[0];
requestPool.RemoveAt(0);
if (net==null)
{
net = GetRequestNet(_url);
}
else
{
net.SetRequestUrl(_url);
}
}
else
{
net = new RequestNet(_url);
}
return net;
}
/// <summary>
/// 初始化公用请求头参数
/// </summary>
protected virtual void InitHeadParamsDict()
{
headParamsDict= new Dictionary<string, string>();
headParamsDict.Add("appName",AppCfg.appName);
//版本
headParamsDict.Add("version",AppCfg.version);
//平台名字 android、ipad、iphone、win、mac
headParamsDict.Add("clientName",AppCfg.clientName);
//设备名称
headParamsDict.Add("deviceName",AppCfg.deviceName);
//设备型号
headParamsDict.Add("deviceModel",AppCfg.deviceModel);
//设备唯一标识符
headParamsDict.Add("deviceUniqueIdentifier",AppCfg.deviceUniqueIdentifier);
//系统版本
headParamsDict.Add("softwareVersion",AppCfg.softwareVersion);
}
/// <summary>
/// 网络请求对象
/// </summary>
public class RequestNet
{
private string requestUrl;
private UnityWebRequest www = null;
// bool =>http是否请求成功 string =>请求成功之后服务器返回的信息 int =>http返回的code码(注意:不是服务器返回的)
private Action<bool, string, int> completeAct;
private Dictionary<string, string> paramsDict;
private int timeout = 5;
private BinaryData? binaryData;
public RequestNet(string _requestUrl)
{
requestUrl = _requestUrl;
}
public void SetRequestUrl(string _url)
{
requestUrl = _url;
}
/// <summary>
/// 设置超时时间
/// </summary>
/// <param name="value">单位s</param>
public void SetTimeout(int value)
{
timeout = value;
if (www != null)
{
www.timeout = timeout;
}
}
void AddHeadParams()
{
if (www==null||headParamsDict==null||headParamsDict.Count==0)
{
return;
}
foreach (var headParam in headParamsDict)
{
www.SetRequestHeader(headParam.Key,headParam.Value);
}
}
/// <summary>
/// 请求
/// </summary>
/// <param name="_method"> post/get/put...</param>
/// <param name="_paramsDict">参数键值对</param>
public void Send(NetMethod _method, Dictionary<string, string> _paramsDict)
{
if (completeAct == null)
{
completeAct = CompleteDispose;
}
if (paramsDict == null)
{
paramsDict = new Dictionary<string, string>();
}
else
{
paramsDict.Clear();
}
paramsDict = _paramsDict;
switch (_method)
{
case NetMethod.GET:
instance.StartCoroutine(SendGetIE());
break;
case NetMethod.POST:
instance.StartCoroutine(SendPostIE());
break;
}
}
/// <summary>
/// Post方式上传文件
/// </summary>
/// <param name="_paramsDict">请求参数键值对</param>
/// <param name="_binaryData">文件对象</param>
public void PostUpload(Dictionary<string,string> _paramsDict,BinaryData _binaryData)
{
binaryData = _binaryData;
paramsDict = _paramsDict;
instance.StartCoroutine(SendPostIE());
}
/// <summary>
/// 请求结束回调
/// </summary>
/// <param name="_completeAct">请求结束的委托</param>
public void OnComplete(Action<bool, string, int> _completeAct)
{
_completeAct += CompleteDispose;
completeAct = _completeAct;
}
private void CompleteDispose(bool isSuccess, string responseStr, int code)
{
this.Dispose();
}
IEnumerator SendPostIE()
{
string url = SpliceUrl();
Debug.Log("<color=green> 【Post:】" + url + "</color>");
WWWForm form = new WWWForm();
foreach (var item in paramsDict)
{
form.AddField(item.Key,item.Value);
}
if (binaryData!=null)
{
string fieldName = ((BinaryData)binaryData).fieldName;
byte[] byteInfoArr = ((BinaryData)binaryData).byteInfoArr;
string fileName = ((BinaryData)binaryData).fileName;
string mimeType = ((BinaryData)binaryData).mimeType;
form.AddBinaryData(fieldName,byteInfoArr,fileName);
}
using (www = UnityWebRequest.Post(requestUrl,form))
{
AddHeadParams();
www.timeout = timeout;
yield return www.SendWebRequest();
string netStr = null;
bool isSuccess = false;
if (www.isNetworkError || www.isHttpError)
{
netStr = www.error;
isSuccess = false;
}
else
{
netStr = www.downloadHandler.text;
isSuccess = true;
}
int code = (int) www.responseCode;
completeAct?.Invoke(isSuccess, netStr, code);
}
}
IEnumerator SendGetIE()
{
string url = SpliceUrl();
Debug.Log("<color=green> 【Get:】" + url + "</color>");
using (www = UnityWebRequest.Get(url))
{
AddHeadParams();
www.timeout = timeout;
yield return www.SendWebRequest();
string netStr = null;
bool isSuccess = false;
if (www.isNetworkError || www.isHttpError)
{
netStr = www.error;
isSuccess = false;
}
else
{
netStr = www.downloadHandler.text;
isSuccess = true;
}
int code = (int) www.responseCode;
completeAct?.Invoke(isSuccess, netStr, code);
}
}
/// <summary>
/// GET模式拼接URL
/// </summary>
/// <returns></returns>
string SpliceUrl()
{
string url = requestUrl + "?";
if (paramsDict != null && paramsDict.Count > 0)
{
int id = 0;
foreach (var item in paramsDict.Keys)
{
string key = item;
string value = paramsDict[key];
if (id < paramsDict.Count - 1)
{
url += key + "=" + value + "&";
}
else
{
url += key + "=" + value;
}
id++;
}
}
return url;
}
/// <summary>
/// 关闭请求对象
/// </summary>
/// <param name="isDestroy"></param>
public void Close(bool isDestroy=false)
{
requestUrl = null;
completeAct = null;
paramsDict = null;
binaryData = null;
if (www!=null)
{
www.Abort();
www.Dispose();
www = null;
}
if (!isDestroy&&requestPool.Count<poolCount&&!requestPool.Contains(this))
{
requestPool.Add(this);
}
}
}
}
}
public static class RequestMoudleExpand{
/// <summary>
/// 释放请求对象
/// </summary>
/// <param name="requestNet">请求对象</param>
/// <param name="isDestroy">是否彻底销毁</param>
public static void Dispose(this RequestManager.RequestNet requestNet,bool isDestroy=false)
{
requestNet?.Close(isDestroy);
requestNet = null;
}
}