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

基于Unity UWR封装JSON请求Wrapper:如何从协程返回字符串?

嘿,这个问题我太熟了!Unity的协程是异步执行的,你没法直接从GetJSON这种同步方法里拿到它的返回值——因为协程还没跑完,同步方法就已经执行结束了。下面给你几个实用的解决方案,帮你搞定这个JSON请求Wrapper,还能实现统一调试的需求:

解决方案1:使用回调函数(最贴合Unity传统异步逻辑)

把处理请求结果的逻辑作为参数传给方法,等协程跑完后自动调用这个回调。这样既能保持异步特性,又能拿到返回的JSON字符串。

修改后的JSONUtils代码:

using System.Collections;
using System;
using UnityEngine;
using UnityEngine.Networking;

namespace Test {
    public class JSONUtils : MonoBehaviour {
        // 全局调试开关,统一控制所有请求的日志
        public bool enableDebugLog = true;

        // 传入成功/失败的回调函数
        public void GetJSON(string uri, Action<string> onSuccess, Action<string> onFailure = null) {
            StartCoroutine(RequestJSONCoroutine(uri, onSuccess, onFailure));
        }

        private IEnumerator RequestJSONCoroutine(string uri, Action<string> onSuccess, Action<string> onFailure) {
            if (enableDebugLog) Debug.Log($"[JSONUtils] 开始请求:{uri}");
            var startTime = Time.realtimeSinceStartup;

            using (UnityWebRequest webRequest = UnityWebRequest.Get(uri)) {
                // 发送请求并等待完成
                yield return webRequest.SendWebRequest();

                // 兼容不同Unity版本的错误判断逻辑
                #if UNITY_2020_1_OR_NEWER
                var isSuccess = webRequest.result == UnityWebRequest.Result.Success;
                #else
                var isSuccess = !webRequest.isNetworkError && !webRequest.isHttpError;
                #endif

                if (enableDebugLog) {
                    var costTime = Time.realtimeSinceStartup - startTime;
                    Debug.Log($"[JSONUtils] 请求{uri}完成,耗时:{costTime:F2}秒");
                }

                if (isSuccess) {
                    onSuccess?.Invoke(webRequest.downloadHandler.text);
                } else {
                    var errorMsg = webRequest.error ?? "未知错误";
                    if (enableDebugLog) Debug.LogError($"[JSONUtils] 请求失败:{errorMsg}");
                    onFailure?.Invoke(errorMsg);
                }
            }
        }
    }
}

使用示例:

在任意场景的脚本里调用,不用关心底层请求逻辑:

public class TestScript : MonoBehaviour {
    [SerializeField] private JSONUtils jsonUtils;

    private void Start() {
        jsonUtils.GetJSON(
            "https://your-api-url.com/data",
            // 成功回调:拿到JSON字符串后处理
            (jsonStr) => {
                Debug.Log("拿到JSON结果:" + jsonStr);
                // 这里可以加JSON解析逻辑,比如用JsonUtility/Json.NET
            },
            // 失败回调:处理错误
            (error) => {
                Debug.LogError("请求出错:" + error);
            }
        );
    }
}
解决方案2:使用Task/Async-Await(适合Unity 2017.1+)

如果你习惯C#的异步语法,可以把协程包装成Task,用async/await写出类似同步的代码,更简洁直观。

修改后的JSONUtils代码:

using System.Collections;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;

namespace Test {
    public class JSONUtils : MonoBehaviour {
        public bool enableDebugLog = true;

        public async Task<string> GetJSONAsync(string uri) {
            var tcs = new TaskCompletionSource<string>();
            StartCoroutine(RequestJSONCoroutine(uri, tcs));
            return await tcs.Task;
        }

        private IEnumerator RequestJSONCoroutine(string uri, TaskCompletionSource<string> tcs) {
            if (enableDebugLog) Debug.Log($"[JSONUtils] 异步请求:{uri}");
            var startTime = Time.realtimeSinceStartup;

            using (UnityWebRequest webRequest = UnityWebRequest.Get(uri)) {
                yield return webRequest.SendWebRequest();

                #if UNITY_2020_1_OR_NEWER
                if (webRequest.result != UnityWebRequest.Result.Success) {
                    tcs.SetException(new System.Exception(webRequest.error));
                } else {
                    tcs.SetResult(webRequest.downloadHandler.text);
                }
                #else
                if (webRequest.isNetworkError || webRequest.isHttpError) {
                    tcs.SetException(new System.Exception(webRequest.error));
                } else {
                    tcs.SetResult(webRequest.downloadHandler.text);
                }
                #endif

                if (enableDebugLog) {
                    var costTime = Time.realtimeSinceStartup - startTime;
                    Debug.Log($"[JSONUtils] 异步请求{uri}完成,耗时:{costTime:F2}秒");
                }
            }
        }
    }
}

使用示例:

调用方法需要标记为async,注意Unity里async void只适合事件/回调方法:

public class TestScript : MonoBehaviour {
    [SerializeField] private JSONUtils jsonUtils;

    private async void Start() {
        try {
            string jsonStr = await jsonUtils.GetJSONAsync("https://your-api-url.com/data");
            Debug.Log("异步拿到JSON:" + jsonStr);
        } catch (System.Exception e) {
            Debug.LogError("异步请求出错:" + e.Message);
        }
    }
}
额外优化:统一请求增强

你可以在这个Wrapper里统一加更多实用功能,比如:

  • 统一添加请求头(比如Token、User-Agent)
  • 设置全局超时时间
  • 请求失败自动重试
  • 统一的请求加载动画管理

所有修改都只需要改JSONUtils这一个脚本,不用逐个场景调整,完美符合你的需求!

内容的提问来源于stack exchange,提问作者Chico3001

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:24:05