【Unity】基于UnityWebRequest简单封装Http的Get/Put/Post

 HttpManager,统一对外接口,目前封装了Get/Put/Post,尚未用的Delete(原理一样)

using System.Collections.Generic;
using System;
using System.Text;

//GET请求会向服务器发送索取数据的请求,从而获取信息。只是用来查询数据,不会修改、增加数据,无论进行多少次操作结果一样。
//PUT请求是向服务器发送数据的,从而改变信息。用来修改数据的内容,但不会增加数据的种类,无论进行多少次操作结果一样。
//POST请求同PUT请求类似,向服务器发送数据。但是会改变数据的种类等资源,会创建新的内容。
//DELETE请求删除某一个资源,尚未使用。
public enum HttpType
{
    Get,
    Post,
    Put,
}

public class HttpManager : MonoSingleton<HttpManager>
{
    private HttpClient httpClient;

    private void Awake()
    {
        httpClient = new HttpClient();
        httpClient.Init();
    }

    private void Update()
    {
        httpClient.UpdateHttpRequest();
    }

    private void OnDestroy()
    {
        httpClient.Clear();
    }

    /// <summary>
    /// Get接口
    /// </summary>
    /// <typeparam name="T">返回的数据类型</typeparam>
    /// <param name="httpId"></param>
    /// <param name="getParameDic"></param>
    public void HttpGet<T>(int httpId,Dictionary<string,string> getParameDic) where T : class
    {
        string getParameStr;
        if(getParameDic == null || getParameDic.Count == 0)
            getParameStr = null;
        else
        {
            StringBuilder stringBuilder = new StringBuilder();
            bool isFirst = true;
            foreach(var item in getParameDic)
            {
                if(isFirst)
                    isFirst = false;
                else
                    stringBuilder.Append('&');
                stringBuilder.Append(item.Key);
                stringBuilder.Append('=');
                stringBuilder.Append(item.Value);
            }
            getParameStr = stringBuilder.ToString();
        }
        httpClient.SendHttpRequest<T>(httpId,HttpType.Get,getParameStr);
    }
    /// <summary>
    /// Get接口
    /// </summary>
    /// <typeparam name="T">返回的数据类型</typeparam>
    /// <param name="httpId"></param>
    /// <param name="getParameStr"></param>
    public void HttpGet<T>(int httpId,string getParameStr) where T : class
    {
        //Get请求通过URL传递数据的格式:URL中请求的文件名后跟着“ ?”;多组键值对,键值对之间用“&”进行分割;URL中包含汉字、特殊符号、需要对这些字符进行编码。
        //url?parame1Name=parame1Value&parame2Name=parame2Value
        httpClient.SendHttpRequest<T>(httpId,HttpType.Get,getParameStr);
    }
    /// <summary>
    /// Get接口
    /// </summary>
    /// <typeparam name="T">返回的数据类型</typeparam>
    /// <param name="httpId"></param>
    public void HttpGet<T>(int httpId) where T : class
    {
        httpClient.SendHttpRequest<T>(httpId,HttpType.Get,null);
    }

    /// <summary>
    /// Post接口
    /// </summary>
    /// <typeparam name="T">返回的数据类型</typeparam>
    /// <param name="httpId"></param>
    /// <param name="postParameStr"></param>
    public void HttpPost<T>(int httpId,string postParameStr) where T : class
    {
        httpClient.SendHttpRequest<T>(httpId,HttpType.Post,postParameStr);
    }
    /// <summary>
    /// Post接口
    /// </summary>
    /// <typeparam name="T">返回的数据类型</typeparam>
    /// <param name="httpId"></param>
    /// <param name="postParame"></param>
    public void HttpPost<T>(int httpId,object postParame) where T : class
    {
        //在传参中定义json
        string postParameStr = FileUtility.DataToJson(postParame);
        //UnityEngine.Debug.Log(postParameStr);
        httpClient.SendHttpRequest<T>(httpId,HttpType.Post,postParameStr);
    }

    /// <summary>
    /// Put接口
    /// </summary>
    /// <param name="httpId"></param>
    /// <param name="putParameStr"></param>
    public void HttpPut(int httpId,string putParameStr)
    {
        httpClient.SendHttpRequest<string>(httpId,HttpType.Put,putParameStr);
    }
    /// <summary>
    /// Put接口
    /// </summary>
    /// <param name="httpId"></param>
    /// <param name="putParame"></param>
    public void HttpPut(int httpId,object putParame)
    {
        string putParameStr = FileUtility.DataToJson(putParame);
        httpClient.SendHttpRequest<string>(httpId,HttpType.Put,putParameStr);
    }

}

HttpClient,实际Http请求处理,没有使用协程等待UnityWebRequest响应,避免了频繁的创建启动协程,

在sendList中记录需要发送的请求,在receiveList中记录已发送,需要等待返回的请求,通过webRequest.isDone判断是否已得到服务器响应

using System.Collections.Generic;
using System;
using UnityEngine.Networking;
using UnityEngine;
using System.Text;

public class HttpClient
{
    private const int webReqTimeout = 15;
    private const int webReqTryCount = 3;

    //发送/接受队列
    private List<HttpPack> sendList = new List<HttpPack>(10);
    private List<HttpPack> receiveList = new List<HttpPack>(10);

    #region --- 外部接口 ---

    public void Init()
    {
    }
    public void Clear()
    {
    }

    public void UpdateHttpRequest()
    {
        HandleSend();
        HandleRecive();
    }

    /// <summary>
    /// 发送服务器请求
    /// </summary>
    /// <typeparam name="T">返回值类型</typeparam>
    /// <param name="httpId"></param>
    /// <param name="httpType"></param>
    /// <param name="parame"></param>
    public void SendHttpRequest<T>(int httpId,HttpType httpType,string parame) where T : class
    {
        AddHttpRequest<T>(httpId,httpType,parame,typeof(T));
    }

    #endregion

    //注册一个请求到发送队列中
    private void AddHttpRequest<T>(int httpId,HttpType httpType,string parame,Type dataType) where T : class
    {
        //将参数设置到HttpPack中然后插入到发送队列里
        //HttpPack pack = GetHttpPack();
        HttpPack<T> pack = new HttpPack<T>();
        pack.id = httpId;
        string apiKey = HttpId.GetHttpApi(httpId);
        if(string.IsNullOrEmpty(apiKey))
        {
            Debug.LogError("为获取到对应的Api : " + httpId);
            return;
        }
        string serviceHost = "******";

        pack.url =  serviceHost + apiKey;
        pack.httpType = httpType;
        pack.dataType = dataType;
        pack.parame = parame;
        pack.tryCount = webReqTryCount;
        //
        sendList.Add(pack);
    }

    //从发送队列中取得一个HttpPack分类型调用请求
    private void HandleSend()
    {
        if(sendList.Count == 0)
            return;

        for(int i = 0; i < sendList.Count; i++)
        {
            HttpPack pack = sendList[i];
            switch(pack.httpType)
            {
                case HttpType.Get:
                    {
                        //Get请求
                        if(!string.IsNullOrEmpty(pack.parame))
                        {
                            //在Url后拼接参数字符串
                            pack.url = string.Format("{0}?{1}",pack.url,pack.parame);
                        }
                        pack.webRequest = new UnityWebRequest(pack.url,UnityWebRequest.kHttpVerbGET);
                        pack.webRequest.downloadHandler = new DownloadHandlerBuffer();
                        pack.webRequest.timeout = webReqTimeout;
                        pack.webRequest.SetRequestHeader("Content-Type","text/json;charset=utf-8");
                        pack.webRequest.SendWebRequest();
                    }
                    break;
                case HttpType.Post:
                    {
                        //Post请求
                        pack.webRequest = new UnityWebRequest(pack.url,UnityWebRequest.kHttpVerbPOST);
                        if(!string.IsNullOrEmpty(pack.parame))
                        {
                            byte[] databyte = Encoding.UTF8.GetBytes(pack.parame);
                            pack.webRequest.uploadHandler = new UploadHandlerRaw(databyte);
                        }
                        pack.webRequest.downloadHandler = new DownloadHandlerBuffer();
                        pack.webRequest.timeout = webReqTimeout;
                        pack.webRequest.SetRequestHeader("Content-Type","text/json;charset=utf-8");
                        pack.webRequest.SendWebRequest();
                    }
                    break;
                case HttpType.Put:
                    {
                        //Put
                        pack.webRequest = new UnityWebRequest(pack.url,UnityWebRequest.kHttpVerbPUT);
                        if(!string.IsNullOrEmpty(pack.parame))
                        {
                            byte[] databyte = Encoding.UTF8.GetBytes(pack.parame);
                            pack.webRequest.uploadHandler = new UploadHandlerRaw(databyte);
                        }
                        pack.webRequest.downloadHandler = new DownloadHandlerBuffer();
                        pack.webRequest.timeout = webReqTimeout;
                        pack.webRequest.SetRequestHeader("Content-Type","text/json;charset=utf-8");
                        pack.webRequest.SendWebRequest();
                    }
                    break;
            }
            receiveList.Add(pack);
        }
        sendList.Clear();
    }

    //处理接收
    private void HandleRecive()
    {
        if(receiveList.Count == 0)
            return;

        for(int i = receiveList.Count - 1; i >= 0; i--)
        {
            HttpPack pack = receiveList[i];
            if(pack.webRequest == null)
            {
                receiveList.Remove(pack);
                continue;
            }

            if(pack.webRequest.isDone)
            {
            }
            else if(pack.webRequest.isHttpError || pack.webRequest.isNetworkError)
            {
                Debug.LogError(pack.webRequest.error);
            }
            else
            {
                continue;
            }

            int responseCode = (int)pack.webRequest.responseCode;
            string responseJson = pack.webRequest.downloadHandler.text;

            //停止
            pack.webRequest.Abort();
            pack.webRequest.Dispose();
            pack.webRequest = null;
            receiveList.Remove(pack);

            if(responseCode != 200 && --pack.tryCount > 0)
            {
                Debug.Log("try " + pack.tryCount);

                sendList.Add(pack);
                continue;
            }

            CheckResponseCode(pack.id,responseCode,responseJson);

            pack.OnData(responseJson,responseCode,pack.id);
        }
    }

    private void CheckResponseCode(int httpId,int responseCode,string responseJson)
    {
        if(responseCode == 200)
            return;

        int codeType = responseCode / 100;
        string apiKey = HttpId.GetHttpApi(httpId);

        switch(codeType)
        {
            case 4:
                Debug.Log(string.Format("{0} : {1} : 客户端错误,请尝试重试操作~",responseCode,apiKey));
                break;
            case 5:
            case 6:
                Debug.Log(string.Format("{0} : {1} : 服务器错误,请尝试重新登陆~",responseCode,apiKey));
                break;
            default:
                Debug.Log(string.Format("{0} : {1} : 未知错误,请尝试重试操作~",responseCode,apiKey));
                break;
        }
    }

}

 HttpPack,记录每次请求数据,在收到服务器返回数据后,通过泛型将json解析后的数据通过广播系统转发给功能模块

using System;
using UnityEngine;
using UnityEngine.Networking;

public abstract class HttpPack
{
    // 事件id
    public int id;
    // 请求地址
    public string url;
    // 协议类型(Get/Post)
    public HttpType httpType;
    // 返回数据类型
    public Type dataType;
    // 请求参数
    public string parame;
    // 重试次数
    public int tryCount;

    public UnityWebRequest webRequest;

    public abstract void OnData(string dataStr,int code,int messageId);
}

public class HttpPack<T> : HttpPack where T : class
{
    public override void OnData(string dataStr,int code,int messageId)
    {
        T data;
        //返回数据只有两种格式:字符串或类
        if(typeof(T).Name == "String")
        {
            data = dataStr as T;
        }
        else
        {
            data = FileUtility.JsonToData<T>(dataStr);
        }
        //广播系统发出消息,功能模块开始处理服务器返回数据
        //MessageBroker.Instance.Publish<T>(data,messageId);
    }
}

HttpId,使用id作为key,既用于Http发送请求(通过自定义特性,可以将id与api绑定,每次发送请求只需要传入id,自动拼接url),又用于广播系统广播消息

public class HttpId
{
    //示例,给id标记api
    [HttpApiKey("Register")]
    public const int registerId = 10001;
    [HttpApiKey("Login")]
    public const int loginId = 10002;
 
    static HttpId()
    {
        System.Reflection.FieldInfo[] fields = typeof(HttpId).GetFields();

        Type attType = typeof(HttpApiKey);
        for(int i = 0; i < fields.Length; i++)
        {
            if(fields[i].IsDefined(attType,false))
            {
                int id = (int)fields[i].GetValue(null);
                object attribute = fields[i].GetCustomAttributes(attType,false)[0];
                string api = (attribute as HttpApiKey).httpApi;
                idDic[id] = api;
            }
        }
    }

    private static Dictionary<int,string> idDic = new Dictionary<int,string>();

    public static string GetHttpApi(int httpId)
    {
        idDic.TryGetValue(httpId,out var api);
        return api;
    }
}


public class HttpApiKey : Attribute
{
    public HttpApiKey(string _httpApi)
    {
        httpApi = _httpApi;
    }
    public string httpApi;
}

UnityWebRequest是一个用来发送网络请求的类,它可以用来从服务器下载文件。当你遇到HTTP/1.1 401 Unauthorized的错误时,意味着服务器拒绝了你的请求,因为你没有提供正确的身份验证信息。HTTP 401错误是一种常见的认证错误,通常是因为以下几个原因: 1. 服务器需要认证,而你的请求中没有包含有效的认证凭证,比如用户名和密码。 2. 你提供的认证凭证不正确,可能是密码错误或者用户名不存在。 3. 认证信息过期或认证方法不被支持。 在Unity中处理401错误,你需要检查你的认证逻辑,确保发送的请求中包含了正确的认证信息。如果你使用的是HTTP Basic Authentication,你需要在请求头中添加一个Authorization字段,其值为"Basic "后接Base64编码的用户名和密码组合。 此外,401错误可能还会涉及到更复杂的认证机制,例如OAuth或Cookie认证,你可能需要根据服务器的具体要求来处理。 示例代码(假设使用HTTP Basic Authentication): ```csharp using UnityEngine; using System.Collections; using System.Net; using System.Text; using UnityEngine.Networking; public class WebRequestDownload : MonoBehaviour { public string userName = "your_username"; public string password = "your_password"; public string url = "http://example.com/file.zip"; void Start() { StartCoroutine(DownloadFile()); } IEnumerator DownloadFile() { using(UnityWebRequest webRequest = UnityWebRequest.Get(url)) { byte[] authValue = new System.Text.ASCIIEncoding().GetBytes(userName + ":" + password); webRequest.SetRequestHeader("Authorization", "Basic " + Convert.ToBase64String(authValue)); yield return webRequest.SendWebRequest(); switch (webRequest.result) { case UnityWebRequest.Result.ConnectionError: case UnityWebRequest.Result.DataProcessingError: Debug.LogError("Error: " + webRequest.error); break; case UnityWebRequest.Result.ProtocolError: Debug.LogError("HTTP Error: " + webRequest.error); break; case UnityWebRequest.Result.Success: // 在这里处理下载的文件 Debug.Log("Downloaded: " + webRequest.downloadHandler.text); break; } } } } ```
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萧然CS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值