Unity协程结合UnityWebRequest异常:未等Token赋值就执行后续逻辑
解决Unity协程未等待Web请求完成就执行后续逻辑的问题
你的问题核心在于Unity协程是异步执行的:调用StartCoroutine(GetToken(...))后,主线程不会暂停等待协程跑完,而是直接继续执行后面的Debug.Log和CreateOrJoinRoom,这时候m_Token还没被赋值,自然会出问题。
下面给两种实用的解决方法:
方法一:将后续逻辑移到协程的成功分支内
直接把需要依赖token的代码放在GetToken协程获取成功的分支里,确保只有拿到token后才执行后续操作:
修改后的ConnectToLiveKit方法:
public void ConnectToLiveKit(string Username, string RoomName){ string query = $"?roomname={RoomName}&username={Username}"; string fullUri = ServiceURL + query; // 把用户名和房间名传给协程,方便后续调用 StartCoroutine(GetToken(fullUri, Username, RoomName)); }
修改后的GetToken协程:
IEnumerator GetToken(string uri, string username, string roomName) { Debug.Log("Getting Token at " + uri + " ..."); UnityWebRequest webRequest = UnityWebRequest.Get(uri); yield return webRequest.SendWebRequest(); string[] pages = uri.Split('/'); int page = pages.Length - 1; switch (webRequest.result) { case UnityWebRequest.Result.ConnectionError: case UnityWebRequest.Result.DataProcessingError: Debug.LogError(pages[page] + ": Error: " + webRequest.error); // 这里添加token获取失败的处理逻辑 break; case UnityWebRequest.Result.ProtocolError: Debug.LogError(pages[page] + ": HTTP Error: " + webRequest.error); // 处理HTTP协议错误 break; case UnityWebRequest.Result.Success: Debug.Log(pages[page] + ":\nReceived: " + webRequest.downloadHandler.text); m_Token = webRequest.downloadHandler.text; // 现在token已赋值,执行后续逻辑 Debug.Log($"Token: {m_Token}"); StartCoroutine(CreateOrJoinRoom(username, roomName)); break; } // 手动释放WebRequest资源(原代码的using被注释了,必须手动处理) webRequest.Dispose(); }
方法二:使用回调委托(更灵活的场景)
如果你的GetToken需要在多个地方调用,且每个地方的后续逻辑不同,可以用回调委托来解耦:
首先定义回调类型:
// token获取成功的回调 private delegate void OnTokenReceived(string token); // token获取失败的回调 private delegate void OnTokenFailed();
修改GetToken协程:
IEnumerator GetToken(string uri, OnTokenReceived onSuccess, OnTokenFailed onFailure) { Debug.Log("Getting Token at " + uri + " ..."); UnityWebRequest webRequest = UnityWebRequest.Get(uri); yield return webRequest.SendWebRequest(); string[] pages = uri.Split('/'); int page = pages.Length - 1; switch (webRequest.result) { case UnityWebRequest.Result.ConnectionError: case UnityWebRequest.Result.DataProcessingError: case UnityWebRequest.Result.ProtocolError: Debug.LogError(pages[page] + ": Error: " + webRequest.error); onFailure?.Invoke(); break; case UnityWebRequest.Result.Success: string token = webRequest.downloadHandler.text; Debug.Log(pages[page] + ":\nReceived: " + token); m_Token = token; onSuccess?.Invoke(token); break; } webRequest.Dispose(); }
调用时传入自定义的后续逻辑:
public void ConnectToLiveKit(string Username, string RoomName){ string query = $"?roomname={RoomName}&username={Username}"; string fullUri = ServiceURL + query; StartCoroutine(GetToken(fullUri, // 成功回调:拿到token后执行的逻辑 (token) => { Debug.Log($"Token: {token}"); StartCoroutine(CreateOrJoinRoom(Username, RoomName)); }, // 失败回调:获取token失败时的处理 () => { Debug.LogError("Failed to retrieve token, cannot join room"); })); }
关键提醒
- 一定要记得释放
UnityWebRequest资源,不管是用using块还是手动调用Dispose(),否则会造成内存泄漏。 - 协程的本质是状态机,
yield return会暂停协程执行,直到等待的操作完成,主线程会继续处理其他任务,这是Unity异步编程的核心特点。
内容的提问来源于stack exchange,提问作者Lee Probert
相关产品推荐
相关产品推荐

