基于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
相关产品推荐
相关产品推荐

