Unity带泛型Action参数的GET请求协程实现技术咨询
嘿,我看了你写的这个Unity泛型HTTP请求方法,思路挺好的,但确实有不少可以优化和完善的点,我从泛型适配、功能补充、代码健壮性这几个方面给你捋捋建议:
1. 先修复现有代码的核心问题
你当前的实现里有个类型不安全的致命问题:当泛型T不是string时,错误分支的callback(www.error)会直接编译失败——因为www.error是字符串类型,无法隐式转换为任意泛型T。这是第一个要解决的问题。
2. 泛型适配优化
2.1 新增JSON反序列化支持
目前你的代码只处理了string类型的响应,但实际开发中绝大多数接口返回的是JSON格式。可以结合Unity自带的JsonUtility(或者项目中常用的Newtonsoft.Json),自动将响应文本反序列化为泛型T:
// 替换原有的类型判断逻辑 try { if (typeof(T) == typeof(string)) { // 直接返回字符串 result.Data = (T)(object)www.downloadHandler.text; } else { // 尝试JSON反序列化 result.Data = JsonUtility.FromJson<T>(www.downloadHandler.text); } } catch (Exception e) { // 捕获反序列化失败的异常 result.IsSuccess = false; result.ErrorMessage = $"解析响应失败: {e.Message}"; }
2.2 用结果类统一回调格式
不要拆分成功/失败回调,建议用一个泛型结果类包装所有返回信息,确保类型安全:
public class RequestResult<T> { public bool IsSuccess { get; set; } public T Data { get; set; } public string ErrorMessage { get; set; } public long ResponseCode { get; set; } // 新增HTTP状态码,方便排查问题 }
这样回调就可以统一为Action<RequestResult<T>>,不管T是什么类型都能安全传递结果。
3. 功能完善建议
3.1 自动释放资源
Unity 2020.1及以上版本支持用using语句自动管理UnityWebRequest的资源,避免内存泄漏:
using (UnityWebRequest www = UnityWebRequest.Get(url)) { yield return www.SendWebRequest(); // 处理响应逻辑 }
3.2 添加实用配置参数
给方法增加超时、请求头、进度回调等常用功能:
public static IEnumerator Get<T>( Action<RequestResult<T>> callback, string url, int timeout = 10, // 默认10秒超时 Dictionary<string, string> headers = null, // 自定义请求头(比如Authorization) Action<float> progressCallback = null) // 下载进度回调 { // 参数校验:提前拦截空URL、空回调的情况 if (string.IsNullOrEmpty(url)) { callback?.Invoke(new RequestResult<T> { IsSuccess = false, ErrorMessage = "URL不能为空" }); yield break; } using (UnityWebRequest www = UnityWebRequest.Get(url)) { // 设置超时 www.timeout = timeout; // 添加请求头 if (headers != null) { foreach (var header in headers) { www.SetRequestHeader(header.Key, header.Value); } } // 发送请求并实时报告进度 var operation = www.SendWebRequest(); while (!operation.isDone) { progressCallback?.Invoke(Mathf.Clamp01(operation.progress)); yield return null; } // 处理响应... } }
3.3 实现泛型POST方法
参考Get方法的结构,实现支持JSON请求体的POST:
public static IEnumerator Post<TRequest, TResponse>( Action<RequestResult<TResponse>> callback, string url, TRequest requestData, int timeout = 10, Dictionary<string, string> headers = null) { using (UnityWebRequest www = UnityWebRequest.PostWwwForm(url)) { // 序列化请求体为JSON string jsonBody = JsonUtility.ToJson(requestData); byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonBody); www.uploadHandler = new UploadHandlerRaw(bodyRaw); www.downloadHandler = new DownloadHandlerBuffer(); www.SetRequestHeader("Content-Type", "application/json"); // 复用Get方法的请求头、超时配置逻辑... yield return www.SendWebRequest(); // 复用Get方法的响应处理逻辑... } }
4. 代码可读性与健壮性优化
- 拆分重复逻辑:把请求头配置、响应解析这些Get/POST通用的逻辑抽成私有方法,避免代码冗余;
- 异常捕获:反序列化、请求过程中可能抛出异常,一定要捕获并转换成友好的错误信息返回;
- 明确命名:比如把方法命名为
GetJsonAsync,更清晰表达功能; - 日志输出:在空回调、参数错误等场景下添加警告日志,方便调试。
优化后的完整Get方法示例
using UnityEngine; using UnityEngine.Networking; using System; using System.Collections; using System.Collections.Generic; using System.Text; public static class HttpRequest { public class RequestResult<T> { public bool IsSuccess { get; set; } public T Data { get; set; } public string ErrorMessage { get; set; } public long ResponseCode { get; set; } } public static IEnumerator Get<T>( Action<RequestResult<T>> callback, string url, int timeout = 10, Dictionary<string, string> headers = null, Action<float> progressCallback = null) { // 参数校验 if (string.IsNullOrEmpty(url)) { callback?.Invoke(new RequestResult<T> { IsSuccess = false, ErrorMessage = "URL不能为空或null" }); yield break; } if (callback == null) { Debug.LogWarning("HttpRequest.Get: 回调为空,请求结果无法返回"); yield break; } using (UnityWebRequest www = UnityWebRequest.Get(url)) { www.timeout = timeout; // 配置请求头 if (headers != null) { foreach (var header in headers) { www.SetRequestHeader(header.Key, header.Value); } } // 发送请求并报告进度 var operation = www.SendWebRequest(); while (!operation.isDone) { progressCallback?.Invoke(Mathf.Clamp01(operation.progress)); yield return null; } // 处理响应结果 var result = new RequestResult<T>(); result.ResponseCode = www.responseCode; if (www.result != UnityWebRequest.Result.Success) { result.IsSuccess = false; result.ErrorMessage = $"请求失败: {www.error} (状态码: {www.responseCode})"; } else { try { if (typeof(T) == typeof(string)) { result.Data = (T)(object)www.downloadHandler.text; } else { result.Data = JsonUtility.FromJson<T>(www.downloadHandler.text); } result.IsSuccess = true; } catch (Exception e) { result.IsSuccess = false; result.ErrorMessage = $"解析响应失败: {e.Message}"; } } callback.Invoke(result); } } }
调用示例
public void GetTest() { string url = "https://api.example.com/data"; StartCoroutine(HttpRequest.Get<MyDataClass>(OnGetCompleted, url, 15, null, OnProgressUpdated)); } private void OnGetCompleted(HttpRequest.RequestResult<MyDataClass> result) { if (result.IsSuccess) { Debug.Log($"获取数据成功: {JsonUtility.ToJson(result.Data)}"); } else { Debug.LogError($"请求失败: {result.ErrorMessage}"); } } private void OnProgressUpdated(float progress) { Debug.Log($"加载进度: {progress:P0}"); } [Serializable] public class MyDataClass { public int Id; public string Name; }
内容的提问来源于stack exchange,提问作者Smokegun
相关产品推荐
相关产品推荐

