🛰️ UnityWebRequest 实践指南

 

🛰️ UnityWebRequest 实践指南在 Unity 中进行网络通信,首选方案早已从 WWW 进化为 UnityWebRequest。它功能强大,支持 GET/POST/PUT/DELETE、文件上传/下载、JSON交互、证书校验、断点续传……一站式搞定。


🌐0.HTTP方法

方法用途简述是否携带数据幂等性典型用途示例
GET获取数据❌ 否✅ 是获取用户、商品详情
POST新增资源 / 提交数据✅ 是❌ 否创建订单、上传表单
PUT更新整个资源✅ 是✅ 是修改用户信息
DELETE删除资源❌/✅ 可选✅ 是删除用户、移除记录

Unity开发中使用场景

类型示例
GET拉配置 / 拉资源列表 / 请求状态
POST登录 / 注册 / 提交反馈 / 创建记录
PUT更新设置 / 修改用户信息
DELETE删除角色 / 移除物品 / 清除缓存

🔹 1. 基础:GET 请求

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

public class SimpleGet : MonoBehaviour
{
   void Start()
  {
       StartCoroutine(GetData());
  }

   IEnumerator GetData()
  {
       UnityWebRequest req = UnityWebRequest.Get("https://jsonplaceholder.typicode.com/posts/1");
       yield return req.SendWebRequest();

       if (req.result == UnityWebRequest.Result.Success)
      {
           Debug.Log(req.downloadHandler.text);
      }
       else
      {
           Debug.LogError(req.error);
      }
  }
}

🔹 2. POST 请求(发送 JSON 数据)

IEnumerator PostJson()
{
   string json = JsonUtility.ToJson(new { username = "伯爵", score = 999 });

   var request = new UnityWebRequest("https://example.com/api/post", "POST");
   byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(json);

   request.uploadHandler = new UploadHandlerRaw(bodyRaw);
   request.downloadHandler = new DownloadHandlerBuffer();
   request.SetRequestHeader("Content-Type", "application/json");

   yield return request.SendWebRequest();

   if (request.result == UnityWebRequest.Result.Success)
  {
       Debug.Log("Response: " + request.downloadHandler.text);
  }
   else
  {
       Debug.LogError("Error: " + request.error);
  }
}

🌀 3. Modern 写法:async/await + UniTask(推荐)

用 UniTask 改写更现代,更易管理任务链和错误:

using Cysharp.Threading.Tasks;
using UnityEngine.Networking;

public async UniTask<string> FetchAsync(string url)
{
   using var request = UnityWebRequest.Get(url);
   await request.SendWebRequest();

   if (request.result == UnityWebRequest.Result.Success)
       return request.downloadHandler.text;
   else
       throw new System.Exception($"网络失败: {request.error}");
}

调用方式:

private async UniTaskVoid Start()
{
   try
  {
       string content = await FetchAsync("https://api.github.com/users/unity3d");
       Debug.Log("✅ Success: " + content);
  }
   catch (System.Exception ex)
  {
       Debug.LogError("❌ 网络错误: " + ex.Message);
  }
}

⚠️ 4. 常见问题与陷阱

问题原因解决方案
request.error == "Unknown Error"HTTPS 请求失败目标站未支持 TLS 或证书问题
中文乱码编码问题Encoding.UTF8.GetString() 手动解码
CORS 跨域问题(WebGL)浏览器安全限制需要服务器设置 Access-Control-Allow-Origin
Post Json 无响应没加头别忘了加 Content-Type: application/json

🔐 5. 自定义请求头(Header)

request.SetRequestHeader("Authorization", "Bearer xxx-token-abc");
request.SetRequestHeader("X-User-ID", "elegant-vampire");

🧪 6. Json 响应结构解析

[System.Serializable]
public class User
{
   public string name;
   public int age;
}

User user = JsonUtility.FromJson<User>(json);

💡 Unity 内置 JsonUtility 不支持复杂嵌套,如字典、数组对象。可使用 Newtonsoft.JsonUtf8Json 替代。


📥 7. 下载文件到本地磁盘

IEnumerator DownloadFile(string url, string localPath)
{
   UnityWebRequest request = UnityWebRequest.Get(url);
   request.downloadHandler = new DownloadHandlerFile(localPath); // ✅ 直接写入磁盘
   yield return request.SendWebRequest();

   if (request.result == UnityWebRequest.Result.Success)
  {
       Debug.Log("文件保存至: " + localPath);
  }
   else
  {
       Debug.LogError("下载失败: " + request.error);
  }
}

🌐 8. 实践场景总结

场景推荐方式
查询接口数据UnityWebRequest.Get() + JsonUtility
上传分数/状态UnityWebRequest.Post() + Json
下载资源文件DownloadHandlerFile
WebGL 通信需处理 CORS 和证书问题
请求队列管理使用 UniTask + 自定义任务队列

9.断点续传示例

功能实现方式
支持中断恢复使用 UnityWebRequest + HTTP Range 请求
保存已下载数据写入本地临时 .part 文件
合并为完整文件下载完成后重命名为最终文件
using System;
using System.IO;
using System.Threading;
using UnityEngine;
using UnityEngine.Networking;
using Cysharp.Threading.Tasks;

public class ResumeDownloader : MonoBehaviour
{
   public string downloadUrl = "https://example.com/bigfile.zip";
   public string savePath = "bigfile.zip";

   private string TempPath => savePath + ".part";

   public async UniTaskVoid StartDownload()
  {
       long existingSize = 0;

       if (File.Exists(TempPath))
           existingSize = new FileInfo(TempPath).Length;

       using var request = UnityWebRequest.Get(downloadUrl);
       request.SetRequestHeader("Range", $"bytes={existingSize}-");

       string directory = Path.GetDirectoryName(savePath);
       if (!Directory.Exists(directory))
           Directory.CreateDirectory(directory);

       request.downloadHandler = new DownloadHandlerBuffer();
       var op = request.SendWebRequest();

       await UniTask.WaitUntil(() => op.isDone, cancellationToken: this.GetCancellationTokenOnDestroy());

       if (request.result != UnityWebRequest.Result.Success && request.responseCode != 206 && request.responseCode != 200)
      {
           Debug.LogError($"❌ 下载失败: {request.error}");
           return;
      }

       var data = request.downloadHandler.data;

       // 追加写入到 .part 文件
       using (var fs = new FileStream(TempPath, FileMode.Append, FileAccess.Write))
      {
           fs.Write(data, 0, data.Length);
      }

       Debug.Log($"✅ 下载分块成功,大小: {data.Length} 字节");

       long totalSize = 0;
       if (request.GetResponseHeader("Content-Range") is string range)
      {
           // Content-Range: bytes 1000-4999/12345
           var totalMatch = System.Text.RegularExpressions.Regex.Match(range, @"/(\d+)");
           if (totalMatch.Success)
               totalSize = long.Parse(totalMatch.Groups[1].Value);
      }

       long currentSize = new FileInfo(TempPath).Length;

       Debug.Log($"🧪 已下载: {currentSize} / {totalSize}");

       if (currentSize >= totalSize)
      {
           File.Move(TempPath, savePath, true);
           Debug.Log($"🎉 下载完成,文件保存在: {savePath}");
      }
       else
      {
           Debug.Log("⏸️ 下载未完成,可稍后继续");
      }
  }

  [ContextMenu("断点续传下载测试")]
   public void StartTest()
  {
       StartDownload().Forget();
  }
}

✅ 面试题推荐(附解析)

  1. UnityWebRequest 与 WWW 的区别? → UnityWebRequest 是现代 API,支持更多功能、更安全,已取代 WWW。

  2. 如何判断 UnityWebRequest 请求成功? → 使用 request.result == UnityWebRequest.Result.Success(Unity 2020.1 起推荐)

  3. 如何解决 WebGL 网络请求跨域失败? → 需要服务端设置 CORS 响应头,如 Access-Control-Allow-Origin: *

  4. JsonUtility 无法解析复杂结构怎么办? → 使用 Newtonsoft.JsonSystem.Text.Json 替代。

  5. async/await 和 Coroutine 区别? async/await 结构清晰,可组合任务、异常处理好;Coroutine 更适合场景逻辑协程。

评论

热门博文