UnityWebRequest教程☀️2021,你还在使用过时的 www API吗?

本文涉及的产品
实时数仓Hologres,5000CU*H 100GB 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
实时计算 Flink 版,5000CU*H 3个月
简介: UnityWebRequest教程☀️2021,你还在使用过时的 www API吗?


🟥  常用网络传输方法

网络传输一般采用Get、Post、Put、Head,

同时还有一些控制的API,或者得到数据之类的API,那么就先从Get说起

1️⃣ Get下载数据

Get可用来下载字符串、数组、图片、AB包、音频等的数据。

当下载完成,可再将数据进行你想要的转换。

    void Start()
    {
        StartCoroutine(SendGetRequest());
    }
 
    IEnumerator SendGetRequest()
    {
        UnityWebRequest uwr = UnityWebRequest.Get("http://www.baidu.com");
        yield return uwr.SendWebRequest();
        if (uwr.isHttpError || uwr.isNetworkError)
        {
            Debug.Log(uwr.error);
        }
        else //请求成功
        {
            Debug.Log("Get:请求成功");
            Debug.Log("下载的数据:" + uwr.downloadedBytes);
        }
    }

 

2️⃣ Post上传数据

Post可以键值对的形式,将数据存在表单WWWForm里,

来上传字符串、图片、音频等的数据。

    void Start()
    {
        StartCoroutine(SendPostRequest());
    }
 
    IEnumerator SendPostRequest()
    {
        WWWForm form = new WWWForm();
        form.AddField("key", "value");
        form.AddField("name", "Chinar");
        UnityWebRequest webRequest = UnityWebRequest.Post("http://www.baidu.com", form);
 
        yield return webRequest.SendWebRequest();
        if (webRequest.isHttpError || webRequest.isNetworkError)
        {
            Debug.Log(webRequest.error);
        }
        else
        {
            Debug.Log("发送成功");
        }
    }

 

3️⃣ Put上传数据

UnityWebRequest数据传输,除了一般我们用的最多的Post、Get,其实还有Put、Head

Post 和 Put 确实很相像,通俗解释就是-------

新建一条记录的话就用post,

更新一条记录的话就用put.

但你用Post更新数据也没问题。

Put上传的东西跟Post相同,同样可以上传音视频、字符串等数据。

    void Start() {
        StartCoroutine(SendPutRequest());
    }
 
    //更新数据
    IEnumerator SendPutRequest() {
        byte[] myData = System.Text.Encoding.UTF8.GetBytes("This is some test data");
        UnityWebRequest www = UnityWebRequest.Put("http://www.my-server.com/upload", myData);
        yield return www.SendWebRequest();
 
        if(www.isNetworkError || www.isHttpError) {
            Debug.Log(www.error);
        }
        else {
            Debug.Log("Upload complete!");
        }
    }

 

4️⃣ Head下载头文件

Head跟Get类似,不同的是Head不会下载文件,只会得到头文件数据。

你可以先了解到这个文件的大小等信息,再让用户决定怎样操作。

使用方法:见下方的 “获取要下载数据的长度”。

 

 

🟧 网络传输的API

有些人又要说了,那我会传输方法了,那怎样怎样得到传输速度呢?

本段就开始讲解UnityWebRequest的各个实用的方法,或者API

1️⃣ 测试网址是否连通

    void Start()
    {
        StartCoroutine(SendRequest());
    }
 
    //测试网址是否连通
    IEnumerator SendRequest()
    {
        Uri uri = new Uri("http://www.baidu.com");
        UnityWebRequest uwr = new UnityWebRequest(uri);
        //等待时间(秒)  超过此数值时,UnityWebReqest的尝试连接将终止
        uwr.timeout = 5;
        yield return uwr.SendWebRequest();
        if (uwr.isHttpError || uwr.isNetworkError)
        {
            Debug.LogError("请求失败:" + uwr.error);
        }
        else //请求成功
        {
            Debug.Log("请求成功");
        }
    }

 

2️⃣ 获取要下载数据的长度

这个API通常用在要下载文件时,先显示要下载文件的大小。

比如《炉石》的是否更新界面、《和平精英》的新场景资源包界面

使用Head的好处是,Head会得到要下载数据的头文件,却不会下载文件。

    void Start()
    {
        StartCoroutine(SendHeadRequest());
    }
 
    private IEnumerator SendHeadRequest(string url)
    {
        UnityWebRequest huwr = UnityWebRequest.Head(url);
        yield return huwr.SendWebRequest();
        if (huwr.isNetworkError || huwr.isHttpError) //如果出错
        {
            Debug.Log(huwr.error); //输出 错误信息
        }
        else
        {
            long totalLength = long.Parse(huwr.GetResponseHeader("Content-Length"));
            print("文件的长度:"+totalLength);
        }
    }

 

3️⃣ 显示下载进度

    public void Start()
    {
        StartCoroutine(DownloadFile());
    }
    
    IEnumerator DownloadFile()
    {
        UnityWebRequest uwr = UnityWebRequest.Get("http://dpv.videocc.net/689be7713e/1/689be7713e7898052861311bd74fc831_3.mp4?pid=1611569020809X1563841");
        uwr.SendWebRequest();
 
        if (uwr.isNetworkError || uwr.isHttpError)
        {
            Debug.Log(uwr.error);
        }
        else
        {
            while (!uwr.isDone)
            {
                GetComponent<Slider>().value = uwr.downloadProgress;
                //Math.floor() 返回小于或等于一个给定数字的最大整数。
                GetComponent<Text>().text = Math.Floor(uwr.downloadProgress * 100) + "%";
                yield return 0;
            }
 
            if (uwr.isDone) //如果下载完成了
            {
                GetComponent<Slider>().value = 1; //改变Slider的值
                GetComponent<Text>().text = 100 + "%";
            }
        }
    }

注意哈,


我们跟上面的Get相比,要注意这儿就没有yield return webRequest.SendWebRequest()了,

而是直接 webRequest.SendWebRequest()

因为yield return后,是直接下载完成或者下载失败。但我们在这儿不需要等待,我们需要时刻知道下载进度。

 

4️⃣ 显示上传进度

跟下载进度类似,是将downloadProgress,变成了uploadProgress。

void Start()
    {
        StartCoroutine(SendPostRequest());
    }
 
    IEnumerator SendPostRequest()
    {
        WWWForm form = new WWWForm();
        form.AddField("key", "value");
        form.AddField("name", "Chinar");
        UnityWebRequest webRequest = UnityWebRequest.Post("http://www.baidu.com", form);
        
        webRequest.SendWebRequest();
            
        if (webRequest.isNetworkError || webRequest.isHttpError)
        {
            Debug.Log(webRequest.error);
        }
        else
        {
            while (!webRequest.isDone)
            {
                GetComponent<Slider>().value = webRequest.uploadProgress;
                //Math.floor() 返回小于或等于一个给定数字的最大整数。
                GetComponent<Text>().text = Math.Floor(webRequest.uploadProgress * 100) + "%";
                yield return 0;
            }
 
            if (webRequest.isDone) //如果下载完成了
            {
                GetComponent<Slider>().value = 1; //改变Slider的值
                GetComponent<Text>().text = 100 + "%";
            }
        }
    }

 

 

5️⃣ 保存下载的文件

...
byte[] results = uwr.downloadHandler.data;
// 注意真机上要用Application.persistentDataPath
CreateFile(Application.streamingAssetsPath + "/MP4/test.mp4", results, uwr.downloadHandler.data.Length);
AssetDatabase.Refresh(); //刷新一下
...
 
    void CreateFile(string path, byte[] bytes, int length)
    {
        FileInfo file = new FileInfo(path);
        if (file.Exists)
            return;
        
        Stream sw;
        sw = file.Create();
        sw.Write(bytes, 0, length);
        sw.Close();
        sw.Dispose();
    }

 

 

6️⃣ 断点续传

断点续传的机制是通过Head先知道要下载文件的大小,然后Get进行下载。

若点了暂停下载,实际是通过break,取消了下载的StartCoroutine。再次开始下载是再次调用StartCoroutine下载。

但再次下载,会先检测本地文件的长度,然后将该长度传入下载请求,从该长度处后开始下载、写入文件,完成断点续传。

    public Button downloadBtn; //开始下载按钮
    public Button controBtn; //暂停下载与恢复下载按钮
 
    private string Url = "http://dpv.videocc.net/689be7713e/1/689be7713e7898052861311bd74fc831_3.mp4?pid=1611569020809X1563841";
    private bool _isPause;
 
    void Start()
    {
        downloadBtn.onClick.AddListener(StartDownload);
        controBtn.onClick.AddListener(DownLoadCon);
    }
 
    public void DownLoadCon()
    {
        if (_isPause)
        {
            _isPause = false;
            Debug.Log("当前继续开始下载");
            StartDownload();
        }
        else
        {
            _isPause = true;
            Debug.Log("当前已暂停下载");
        }
    }
 
    private void StartDownload()
    {
        // 注意真机上要用Application.persistentDataPath
        StartCoroutine(DownloadFile(Url, Application.streamingAssetsPath + "/MP4/test.mp4"));
    }
 
    private IEnumerator DownloadFile(string url, string filePath)
    {
        UnityWebRequest huwr = UnityWebRequest.Head(url);
        yield return huwr.SendWebRequest();
        if (huwr.isNetworkError || huwr.isHttpError)
        {
            Debug.Log(huwr.error);
        }
        else
        {
            long totalLength = long.Parse(huwr.GetResponseHeader("Content-Length"));
            print("文件的全部长度:" + totalLength);
 
            string dirPath = Path.GetDirectoryName(filePath);
            if (!Directory.Exists(dirPath)) //判断路径是否存在
            {
                Directory.CreateDirectory(dirPath);
            }
 
            //创建一个文件流,指定路径为filePath,模式为打开或创建,访问为写入
            using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write))
            {
                long nowFileLength = fs.Length; //当前本地的文件长度
                if (nowFileLength < totalLength)
                {
                    // FileStream.Seek:从当前文件一开始,向后移动nowFileLength个字节,将该流的当前位置设置为给定值。
                    fs.Seek(nowFileLength, SeekOrigin.Begin);
                    UnityWebRequest uwr = UnityWebRequest.Get(url); //创建UnityWebRequest对象,将Url传入
                    uwr.SetRequestHeader("Range", "bytes=" + nowFileLength + "-" + totalLength);
                    uwr.SendWebRequest();
 
                    if (uwr.isNetworkError || uwr.isHttpError)
                    {
                        Debug.Log(uwr.error);
                    }
                    else
                    {
                        long index = 0;
                        while (nowFileLength < totalLength) //只要下载没有完成,一直执行此循环
                        {
                            print(nowFileLength);
                            if (_isPause)    //暂停下载
                                break;
                            yield return null;
                            byte[] data = uwr.downloadHandler.data;
                            if (data != null)
                            {
                                long length = data.Length - index;
                                fs.Write(data, (int) index, (int) length);
                                index += length;
                                nowFileLength += length;
                                if (nowFileLength >= totalLength)
                                {
                                    print("下载完成!");
                                    AssetDatabase.Refresh();
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

小提示:

FileStream.Seek(long offset, SeekOrigin origin):有两个参数。第一参数规定文件指针以字节为单位移动的距离。第二个规定开始计算的位置

SeekOrigin是一个枚举,包含三个值:Begin、Current、End。

  • aFile.Seek(8,SeekOrigin.Begin)---------将文件的指针移动到第八个字节。起始位置就是文件的第一个字节
  • aFile.Seek(-5,SeekOrigin.End); 从文件的末尾向前查找五个字节
  • aFile.Seek(2,SeekOrigin.Current);
相关文章
|
20天前
|
人工智能 API 开发工具
【重磅发布】 免费领取阿里云百炼AI大模型100万Tokens教程出炉,API接口实战操作,DeepSeek-R1满血版即刻体验!
阿里云百炼是一站式大模型开发及应用构建平台,支持开发者和业务人员轻松设计、构建大模型应用。通过简单操作,用户可在5分钟内开发出大模型应用或在几小时内训练专属模型,专注于创新。
461 88
【重磅发布】 免费领取阿里云百炼AI大模型100万Tokens教程出炉,API接口实战操作,DeepSeek-R1满血版即刻体验!
|
24天前
|
机器学习/深度学习 人工智能 Serverless
👉「免费满血DeepSeek实战-联网搜索×Prompt秘籍|暨6平台横评」
满血 DeepSeek 免费用!支持联网搜索!创作声明:真人攥写-非AI生成,Written-By-Human-Not-By-AI
2527 9
👉「免费满血DeepSeek实战-联网搜索×Prompt秘籍|暨6平台横评」
|
1月前
|
JSON 数据可视化 API
Python 中调用 DeepSeek-R1 API的方法介绍,图文教程
本教程详细介绍了如何使用 Python 调用 DeepSeek 的 R1 大模型 API,适合编程新手。首先登录 DeepSeek 控制台获取 API Key,安装 Python 和 requests 库后,编写基础调用代码并运行。文末包含常见问题解答和更简单的可视化调用方法,建议收藏备用。 原文链接:[如何使用 Python 调用 DeepSeek-R1 API?](https://apifox.com/apiskills/how-to-call-the-deepseek-r1-api-using-python/)
|
1月前
|
缓存 自然语言处理 安全
快速调用 Deepseek API!【超详细教程】
Deepseek 强大的功能,在本教程中,将指导您如何获取 DeepSeek API 密钥,并演示如何使用该密钥调用 DeepSeek API 以进行调试。
|
1月前
|
存储 人工智能 安全
如何调用 DeepSeek-R1 API ?图文教程
首先登录 DeepSeek 开放平台,创建并保存 API Key。接着,在 Apifox 中设置环境变量,导入 DeepSeek 提供的 cURL 并配置 Authorization 为 `Bearer {{API_KEY}}`。通过切换至正式环境发送请求,可实现对话功能,支持流式或整体输出。
1836 15
|
3月前
|
网络协议 API
检测指定TCP端口开放状态免费API接口教程
此API用于检测指定TCP端口是否开放,支持POST/GET请求。需提供用户ID、KEY、目标主机,可选指定端口(默认80)和地区(默认国内)。返回状态码、信息提示、检测主机、端口及状态(开放或关闭)。示例中ID和KEY为公共测试用,建议使用个人ID和KEY以享受更高调用频率。
92 14
|
3月前
|
前端开发 JavaScript API
提取网页所有链接免费API接口教程
此API用于提取指定网页内的所有链接信息并进行分类,支持POST和GET请求方式。需提供用户ID、KEY及目标网址等参数,可选指定访问节点。返回结果包括状态码、信息提示及各类链接集合,如图片、视频、文档等。示例中展示了请求格式与返回数据结构。
|
3月前
|
API
获取网页状态码[可指定地域]免费API接口教程
该接口用于获取指定网址的访问状态码,支持从国内、香港、美国等地域节点访问。通过POST或GET请求,需提供用户ID、KEY及目标网址等参数。返回结果包括状态码和信息提示。 示例:https://cn.apihz.cn/api/wangzhan/getcode.php?id=88888888&key=88888888&type=1&url=www.apihz.cn。
|
3月前
|
缓存 算法 API
查询域名WHOIS信息免费API接口教程
该API用于查询顶级域名的WHOIS信息,不支持国别域名和中文域名。通过POST或GET请求,需提供用户ID、KEY及待查询域名。返回信息包括域名状态、注册商、时间等详细数据。示例与文档见官网。
|
3月前
|
API
icp备案查询免费API接口教程
该接口用于查询指定域名的ICP备案信息,支持POST或GET请求方式。请求时需提供用户ID、用户KEY及待查询的域名,可选参数为查询通道。响应中包含状态码、消息内容、备案号、备案主体、域名及审核时间等信息。示例中提供了GET和POST请求方式及返回数据样例。