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

本文涉及的产品
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
实时计算 Flink 版,5000CU*H 3个月
实时数仓Hologres,5000CU*H 100GB 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);
相关文章
|
6月前
|
数据采集 监控 安全
各种业务场景调用API代理的API接口教程
API代理的API接口在各种业务场景中具有广泛的应用,本文将介绍哪些业务场景可以使用API代理的API接口,并提供详细的调用教程和代码演示,同时,我们还将讨论在不同场景下使用API代理的API接口所带来的好处。
|
4天前
|
API
将秒数转换为时间免费API接口教程
该API用于将指定秒数转换为年、日、时、分、秒。支持指定转换类型。请求地址为 `https://cn.apihz.cn/api/time/stime.php`,需提供ID、密钥、类型和秒数参数。返回结果包含转换后的年、日、时、分、秒等信息。示例请求:`https://cn.apihz.cn/api/time/stime.php?id=88888888&key=88888888&type=1&s=123456`。更多详情见 [文档](https://www.apihz.cn/api/timestime.html)。
将秒数转换为时间免费API接口教程
|
1天前
|
API
车牌号归属地查询免费API接口教程
本接口用于根据车牌号查询社会车辆的归属地,不支持军车、使馆等特殊车牌。请求地址为 `https://cn.apihz.cn/api/other/chepai.php`,支持 POST 和 GET 请求。请求参数包括 `id`、`key` 和 `words`,返回数据包含车牌归属地信息。示例请求:`https://cn.apihz.cn/api/other/chepai.php?id=88888888&key=88888888&words=川B1234`。
32 21
|
4天前
|
API
图片压缩+格式转换免费API接口教程
这是一个免费的图片压缩和格式转换API接口,支持GET和POST请求。请求地址为 `https://cn.apihz.cn/api/img/yasuo.php`,需提供 `id`、`key`、`img` 等参数。返回数据包含处理后的图片URL和其他相关信息。更多详情请参考:https://www.apihz.cn/api/imgyasuo.html
|
3天前
|
API
天气预报-腾讯天气-7天-IP查询版免费API接口教程
根据IP地址自动查询该IP归属地7天天气预报的腾讯天气API。请求地址为`https://cn.apihz.cn/api/tianqi/tengxunip.php`,支持GET和POST请求。需提供ID、Key和IP地址作为参数。返回数据包含天气预报信息。
|
2天前
|
前端开发 JavaScript API
取网页纯文本内容免费API接口教程
该API用于获取指定网页的纯文本内容,去除HTML标签、CSS和JS等元素。支持POST和GET请求,需提供ID、Key、URL等参数。请求示例:https://cn.apihz.cn/api/wangzhan/getyuan.php?id=88888888&key=88888888&url=www.apihz.cn&dy=1。返回纯文本数据。
|
1月前
|
API 微服务
Traefik 微服务 API 网关教程(全)
Traefik 微服务 API 网关教程(全)
|
2月前
|
存储 JSON API
实战派教程!Python Web开发中RESTful API的设计哲学与实现技巧,一网打尽!
在数字化时代,Web API成为连接前后端及构建复杂应用的关键。RESTful API因简洁直观而广受欢迎。本文通过实战案例,介绍Python Web开发中的RESTful API设计哲学与技巧,包括使用Flask框架构建一个图书管理系统的API,涵盖资源定义、请求响应设计及实现示例。通过准确使用HTTP状态码、版本控制、错误处理及文档化等技巧,帮助你深入理解RESTful API的设计与实现。希望本文能助力你的API设计之旅。
64 3
|
3月前
|
JavaScript API PHP
一言API搭建教程:搭建属于自己的文言API接口
这篇文章介绍了如何搭建一个属于自己的文言API接口。文章首先介绍了准备工作,包括代码编辑器和两个文件的创建。然后详细说明了如何将代码复制到php文件中并上传至网站根目录。最后给出了一个示例代码来调用文言API接口。整个过程非常简单。
64 1
|
3月前
|
开发框架 .NET API
在IIS上部署ASP.NET Core Web API和Blazor Wasm详细教程
在IIS上部署ASP.NET Core Web API和Blazor Wasm详细教程
182 3