You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:35:01