精华内容
下载资源
问答
  • webrequest
    千次阅读
    2022-04-28 12:16:03

    UnityWebRequest关于对timeout理解

    从字面意思理解的timeout是未响应时间。但其实并不是。

    问题:

    1. timeout是未响应时间吗?
    2. 设置一个timeout,超过这个timeout,但是还在downloading,那算timeout吗?
    3. 有网络后,在timeout范围内下载源(UnityWebRequest)还在继续吗?
    4. 怎么解决timeout内,unity并未提供有效的接口,断网的业务需求?

    答案:

    1. 不是。
    2. 算timeout。
    3. 会继续。
    4. 关注downloadedBytes,实现业务需求.

    应用场景:设置了timeout,资源还在下载,timeout了,下载源(UnityWebRequest)会中断,底层逻辑代码里unity的机制会中断掉这个下载源,算timeout. 。以及没有网络后,下载源还在继续,不到timeout不会中断.

    结论:UnityAPI—UnityWebRequest的timeout在官网技术文档的解释是:Sets UnityWebRequest to attempt to abort after the number of seconds in timeout have passed.(意思是设置一个时长,时间到了就会abort这个UnityWebRequest,不管是否还在下载中 。)简单理解为timeout就是一个下载完成的时间,超过了就下载中断。</

    更多相关内容
  • UnityWebRequest远端下载,支持断点续传、多文件同时下载 亲测可以使用 可以自定义修改进度
  • 2022年 UnityWebRequest.isNetworkError”已过时,弃用,解决方法
  • 基于UnityWebRequest,支持断点下载。简单好用下载快速。两个主要脚本文件,以及一个DownTest测试文件。使用时直接调用即可,具体参看Test脚本的使用
  • 前言 PowerShell能干什么呢?PowerShell首先是个Shell,定义好了一堆命令与操作系统,特别是与文件系统交互,能够启动应用程序,甚至操纵应用程序;第二,PowerShell允许将几个命令组合起来放到文件里执行,实现文件...
  • unity最新支持断点续传的方便,代码简单易懂。demo版本unity2021,参考文章:https://blog.csdn.net/chunyu90225/article/details/118545989
  • UnityWebRequest 简单资源下载 支持断点续传,下载进度,下载速度(每秒) 使用方法:开启一个协程,调用DownLoadFile即可, 需要传入3个Action,分别时下载进度,下载文件与当前文件总大小进度,和下载速度
  • 热交换文件路径。 为映射的路径创建307内部重定向。 两种为文件创建重定向的方法: 单个文件 - 重定向特定的单个文件。 ... 域 - 将所有请求从一个域重定向到另一个域(路径名和搜索将被保存)。...在现场无需更改即可享受...
  • Unity 最新UnityWebRequest下载网络资源,支持断点续传、多文件同时下载,同时显示下载进度,和 显示网速,今天贴出来和大家分享 删除Editor文件夹即可
  • 使用 WebRequest() 函数在 MQL5.com 网站上发布含有图像的消息例程。这是如何使用登录名和口令进行认证,并在消息里插入图像的例子。
  • FileDownloadHandler 自定义下载处理程序的UnityWebRequest
  • Unity 中通过UnityWebRequest 以GET形式传authorization 的参数请求数据。 注意: 以Header头文件的形式发送请求,authorization要放入请求头部。 以头文件形式发起请求进行Token验证,token为Authorization中的...
  • Unity 中通过UnityWebRequest 以POST形式传JSON格式(键值对格式)的参数请求数据。
  • UnityWebRequest下载网络资源的小框架,支持断点续传、多文件同时下载。主要功能只有两个脚本,是用的Unity5.6.2导出的。 注意:只能断点续传网络资源,本地资源无法断点续传!
  • js代码-WebRequest

    2021-07-16 16:32:29
    js代码-WebRequest
  • 本篇文章对WebRequest.RegisterPrefix的使用进行了详细的分析介绍,需要的朋友参考下
  • 使用unity自带的UnityWebRequest实现文件分段下载,可扩展断点续传,功能已经写好,只需自己控制断点续传本地缓存文件长度读取并传入函数参数即可
  • Android_webRequest-master.zip,Android_webRequest-master,.project,project.properties,src,com,example,demo_webrequest,MainActivity.java,volley,RequestStringActivity.java,utils,BitmapCache.java,...
  • WebRequestWatcher 简单的Chrome扩展程序可帮助调试chrome.webRequest API
  • 一、技术概述 1、描述这个技术是做什么? ...2、学习该技术的原因? 项目需要,防止使用C#原生的网络库,加快开发速度 3、技术的难点在哪里 ...Unity仅提供了基础的功能,如何把这些功能构造成一个能够稳定业务开发的...
  • Unity之UnityWebRequest和使用

    千次阅读 2022-03-10 22:53:13
    if (webRequest.isHttpError || webRequest.isNetworkError) { Debug.Log(webRequest.error); } else { Debug.Log("发送成功"); } } } 3.Put方法 Put方法将数据发送到远程的服务器。例如:文件上传 using System....

    一、前言

    1. UnityWebRequest

     官方描述:

    UnityWebRequest 提供了一个模块化系统,用于构成 HTTP 请求和处理 HTTP 响应。UnityWebRequest 系统的主要目标是让 Unity 游戏与 Web 浏览器后端进行交互。该系统还支持高需求功能,例如分块 HTTP 请求、流式 POST/PUT 操作以及对 HTTP 标头和动词的完全控制。

    从官方描述来看,对于UnityWebRequest类的升级更大程度代表了Unity对于Webgl网页浏览器支持的优化。

    2.WWW类

    其实5.4版本的时候就出了新的API UnityWebRequest用于替代WWW,有些较大的文件下载需要断点续传的功能(即下载了一部分突然中断下载后,再次下载直接从上次下载的地方继续下载,而不是重新下载)就需要使用HttpWebRequest或UnityWebRequest,在2017版本中WWW是还没有被弃用的,2018版本我没有试过,2019是已经被弃用的,使用的时候可以看到这个类被画上了绿色波浪。

    这里大体的描述一下,后面还可能会持续深入解剖。下面讲述一下这个类的一些常用接口和使用

    二、常用方法Get、Post、Put和Head

    UnityWebRequest

    架构:

    UnityWebRequest 生态系统将 HTTP 事务分解为三个不同的操作:

    • 向服务器提供数据
    • 从服务器接收数据
    • HTTP 流量控制(例如,重定向和错误处理)

    UnityWebRequest由三个元素组成:
    1 UpLoadHandler处理数据将数据上传到服务器的对象;
    2 DownLoadHandler从服务器下载数据的对象;
    3 UnityWebRequest负责与HTTP通信并管理上面两个对象。还处理 HTTP 流量控制。此对象是定义自定义标头和 URL 的位置,也是存储错误和重定向信息的位置。

    更多描述请看官网手册:https://docs.unity.cn/cn/2019.4/Manual/UnityWebRequest.html 

     (1)常用方法:

    方法作用
    SendWebRequest()开始与远程服务器通信。在调用此方法之后,有必要的话UnityWebRequest将执行DNS解析,将HTTP请求发送到目标URL的远程服务器并处理服务器的响应。
    Get(url)创建一个HTTP为传入URL的UnityWebRequest对象
    Post(url)向Web服务器发送表单信息
    Put(url)将数据上传到Web服务器
    Abort()直接结束联网
    Head()创建一个为传输HTTP头请求的UnityWebRequest对象
    GetResponseHeader()返回一个字典,内容为在最新的HTTP响应中收到的所有响应头

    (2)构造函数

    public UnityWebRequest(); 
    public UnityWebRequest(Uri uri);
    public UnityWebRequest(Uri uri,string method);
    public UnityWebRequest(Uri uri,string method,Networking.DownloadHandler downloadHandler, 
    						Networking.UploadHandler uploadHandler);
    
    参数含义
    URLurl网址信息或本地文件路径信息
    method相当于方法名,只有GET, POST, PUT, HEAD四种,默认为GET,一旦调用SendWebRequest(),就无法更改
    downloadHandler下载数据的委托方法
    uploadHandler上传数据的委托方法

    下面介绍一下一些经常用的接口。介绍之前先简单聊聊GET、POST和PUT这三种方式的区别

    1.Get:一般用于向服务器获取信息,举例:后台服务器有一个接口http://127.0.0.1/Get/?studentName=张三,这个接口负责返回学生名字为张三的数据,我们在提交get的时候,服务器会接收studentName下的值,通过这个值来进行逻辑处理,使用Get我们要访问得值是暴露在浏览器中的,如果是用户名密码这样的重要信息被暴露后果将不堪设想,所以像网页中搜索栏需要条件来获取信息的功能,就可以使用Get的方法来实现。

    2.Post:这种方式就是为了解决Get访问时信息暴露的危险,使用Post访问时表单中的内容不会暴露,安全性更高,一般用于网页用户登录等重要信息上

    3.Put:这种方式用于将数据发送到远程的服务器。比如文件上传。

    1.Get方法

    (1) 使用静态类创建UnityWebRequest获取Txt文本信息

    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using UnityEngine.UI;
    using UnityEngine;
    using UnityEngine.EventSystems;
    using UnityEngine.Networking;
    using System;
    
    public class AAA : MonoBehaviour
    {
        void Start()
        {
            StartCoroutine("GetDataB", "Test.txt");
        }
    
        #region 创建persistentDataPath文件夹
        IEnumerator GetDataB(string fileName)
        {
            //1.url地址
            string fromPath = Application.streamingAssetsPath + "/" + fileName;
            //2.创建一个UnityWebRequest类 method属性为Get
            UnityWebRequest request = UnityWebRequest.Get(fromPath);
            //3.等待响应时间,超过5秒结束
            request.timeout = 5;
            //4.发送请求信息
            yield return request.SendWebRequest(); 
    
            //5.判断是否下载完成
            if (request.isDone)
            {
                //6.判断是否下载错误
                if (request.isHttpError || request.isNetworkError)
                    Debug.Log(request.error);
                else
                    Debug.Log(request.downloadHandler.text);
            }
        }
    
        #endregion
    }
    

    (2) 使用构造来创建

    注意:这里为什么要用两种方式呢?因为静态类创建(UnityWebRequest.Get)的Request是自带DownloadHandler和UploadHandler的,而构造创建(new UnityWebRequest )是没有的,需要自己手动创建赋值,注意不要踩坑哦!!

    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using UnityEngine.UI;
    using UnityEngine;
    using UnityEngine.EventSystems;
    using UnityEngine.Networking;
    using System;
    
    public class AAA : MonoBehaviour
    {
        void Start()
        {
            StartCoroutine("GetDataB", "Test.txt");
        }
    
        #region 创建persistentDataPath文件夹
        IEnumerator GetDataB(string fileName)
        {
    
            string fromPath = Application.streamingAssetsPath + "/" + fileName;
            Uri uri = new Uri(fromPath);
            //UnityWebRequest request = UnityWebRequest.Get(fromPath);
            UnityWebRequest request =new UnityWebRequest(uri); //使用构造
            request.timeout = 5;//等待响应时间,超过5秒结束
    
            /*使用构造没有DownloadHandler和UploadHandler,所以要创建赋值,这里只用到了下载,所以可以不用创建UploadHandler
             * 下面罗列了三种不同类型的DownloadHandler
             1.DownloadHandlerBuffer 读取文件存储
             2.DownloadHandlerTexture 读取图片
             3.DownloadHandlerFile 下载文件到本地
             */
            DownloadHandlerBuffer Download = new DownloadHandlerBuffer();
            request.downloadHandler = Download;
    
            yield return request.SendWebRequest();
    
            if (request.isDone)
            {
                if (request.isHttpError || request.isNetworkError)
                    Debug.Log(request.error);
                else 
                    Debug.Log(request.downloadHandler.text);
            }
            
        }
    
        #endregion
    
    }
    

     2.Post方法

    Post方法将一个表上传到远程的服务器,一般来说我们登陆某个网站的时候会用到这个方法,我们的账号密码会以一个表单的形式传过去。

    using System.Collections;
    using UnityEngine;
    using UnityEngine.Networking;
    
    /// <summary>
    /// 网络请求测试
    /// </summary>
    public class ChinarWebRequest : MonoBehaviour
    {
        void Start()
        {
            StartCoroutine(Post());
        }
        /// <summary>
        /// 开启一个协程,发送请求
        /// </summary>
        /// <returns></returns>
        IEnumerator Post()
        {
            WWWForm form = new WWWForm();
            //键值对
            form.AddField("key",  "value");
            form.AddField("name", "Chinar");
            //请求链接,并将form对象发送到远程服务器
            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方法

    Put方法将数据发送到远程的服务器。例如:文件上传

    using System.Collections;
    using UnityEngine;
    using UnityEngine.Networking;
    
    /// <summary>
    /// 网络请求测试
    /// </summary>
    public class ChinarWebRequest : MonoBehaviour
    {
        void Start()
        {
            StartCoroutine(Upload());
        }
        
        /// <summary>
        /// 开启协程
        /// </summary>
        /// <returns></returns>
        IEnumerator Upload()
        {
            byte[] myData = System.Text.Encoding.UTF8.GetBytes("Chinar的测试数据");
            using (UnityWebRequest uwr = UnityWebRequest.Put("http://www.baidu.com", myData))
            {
                yield return uwr.SendWebRequest();
    
                if (uwr.isNetworkError || uwr.isHttpError)
                {
                    Debug.Log(uwr.error);
                }
                else
                {
                    Debug.Log("上传成功!");
                }
            }
        }
    }
    

    4.Abort方法

    Abort方法会尽快结束联网,可以随时调用此方法。
    如果 UnityWebRequest尚未完成,那么 UnityWebRequest将尽快停止上传或下载数据。

    中止的 UnityWebRequests被认为遇到了系统错误。isNetworkError或isHttpError属性将返回true,error属性将为“User Aborted”。

    5.Head方法 

    Head方法与Get方法用法一致,都是传入一个URL。

    关于head这个方法解释推荐文章:https://www.jianshu.com/p/49ebc4a78474

    根据这个文章特点的截图 我简单聊聊Head作用 :

     1.第一条就是只请求资源头部,网页的body主体是不显示的。大家可以先用get请求一个www.baidu.com查看

    接下来我们使用Head来请求

     2.检查超链接有效性,当链接出现问题时会返回一个错误码,上方链接文章有对应错误码的中文描述。使用get、post也可以测试有效性,但是这些方式访问成功会返回body主体,所以使用head访问可以节省网络资源

    3.网页是否被修改,举个例子,我们将一个静态网页使用MD5加密后存入数据库,在head中加入这个html被加密后的数据进行数据库访问判断,如果这个静态网页被修改访问就会出现问题。不过这是很久之前的版本用的方法,现在基本使用的时token进行验证

    4.第四点就是头包含的这些信息了,例如我们需要获取安全验证信息来进心判断操作,如果使用GET、PUST等方式访问,就会连带body主体一起获取,大大浪费资源。

    下面是UnityWebRequest.Head的请求方式:一般与下面的GetResponseHeader方法配合使用获取文件大小的,后面断电续传中会有用到。

        /// <summary>
        /// 开启一个协程,发送请求
        /// </summary>
        /// <returns></returns>
        IEnumerator SendRequest()
        {
            UnityWebRequest uwr = UnityWebRequest.Head("www.baidu.com");       //创建UnityWebRequest对象
            yield return uwr.SendWebRequest();                                 //等待返回请求的信息
            if (uwr.isHttpError || uwr.isNetworkError)                         //如果请求失败,或是 网络错误
            {
                Debug.Log(uwr.error); //打印错误原因
            }
            else //请求成功
            {
                Debug.Log("Head:请求成功");
            }
        }

    6.GetResponseHeader方法

    GetResponseHeader方法可以用来获取请求文件的长度 传入参数 "Content-Length"字符串,表示获取文件内容长度。

     IEnumerator SendRequest()
        {
            UnityWebRequest uwr = UnityWebRequest.Head("www.baidu.com"); //创建UnityWebRequest对象
            yield return uwr.SendWebRequest();                                 //等待返回请求的信息
            if (uwr.isHttpError || uwr.isNetworkError)                         //如果其 请求失败,或是 网络错误
            {
                Debug.Log(uwr.error); //打印错误原因
            }
            else //请求成功
            {
                long totalLength = long.Parse(uwr.GetResponseHeader("Content-Length")); //首先拿到文件的全部长度
                Debug.Log($"totalLength:{totalLength}" );//打印文件长度
            }
        }

    三、常用属性

    属性类型含义
    timeoutint等待时间(秒)超过此数值是 UnityWebReqest的尝试连接将终止
    isHttpErrorboolHTTP响应出现出现错误
    isNetworkErrorbool系统出现错误
    errorstring描述 UnityWebRequest对象在处理HTTP请求或响应时遇到的任何系统错误
    downloadProgressfloat表示从服务器下载数据的进度
    uploadProgressfloat表示从服务器上传数据的进度
    isDonebool是否完成与远程服务器的通信
    SendWebRequestUnityWebRequestAsyncOperation发送信息访问

    四、案例 

    一、断点续传

    记录已经下载到的本地文件大小,向资源服务器发送请求时,通过请求头实现拿到剩下需要下载的内容,然后接着下载
    确保对同一个资源文件的下载操作,就不存在资源会下载错误的情况,如果你在断点续传的阶段发现资源服务器上的资源已经更新,那就得删除之前下载的文件然后重新下载。

    using System;
    using System.Collections;
    using System.IO;
    using UnityEngine;
    using UnityEngine.Networking;
    using UnityEngine.UI;
    
    public class ChinarBreakpointRenewal : MonoBehaviour
    {
        private bool _isStop;           //是否暂停
    
        public Slider ProgressBar;      //进度条
        public Text SliderValue;        //滑动条值
        public Button startBtn;        //开始按钮
        public Button pauseBtn;        //暂停按钮
        string Url = "https://downsc.chinaz.net/Files/DownLoad/sound1/201808/10447.wav";
    
        /// <summary>
        /// 初始化UI界面及给按钮绑定方法
        /// </summary>
        void Start()
        {
            //初始化进度条和文本框
            ProgressBar.value = 0;
            SliderValue.text = "0.0%";
    
            //开始、暂停按钮事件监听
            startBtn.onClick.AddListener(OnClickStartDownload);
            pauseBtn.onClick.AddListener(OnClickStop);
        }
    
    
        //开始下载按钮监听事件
        public void OnClickStartDownload()
        {
            //开启协程 *注意真机上要用Application.persistentDataPath路径*
            StartCoroutine(DownloadFile(Url, Application.streamingAssetsPath + "/MP4/test.mp4", CallBack));
        }
    
    
        /// <summary>
        /// 协程:下载文件
        /// </summary>
        /// <param name="url">请求的Web地址</param>
        /// <param name="filePath">文件保存路径</param>
        /// <param name="callBack">下载完成的回调函数</param>
        /// <returns></returns>
        IEnumerator DownloadFile(string url, string filePath, Action callBack)
        {
            UnityWebRequest huwr = UnityWebRequest.Head(url); //使用Head方法可以获取到文件的全部长度
            yield return huwr.SendWebRequest();//发送信息请求
            //判断请求或系统是否出错
            if (huwr.isNetworkError || huwr.isHttpError) 
            {
                Debug.Log(huwr.error); //出现错误 输出错误信息
            }
            else
            {
                long totalLength = long.Parse(huwr.GetResponseHeader("Content-Length")); //首先拿到文件的全部长度
                string dirPath = Path.GetDirectoryName(filePath);//获取文件的上一级目录
                if (!Directory.Exists(dirPath)) //判断路径是否存在
                {
                    Directory.CreateDirectory(dirPath);//不存在创建
                }
    
                /*作用:创建一个文件流,指定路径为filePath,模式为打开或创建,访问为写入
                 * 使用using(){}方法原因: 当同一个cs引用了不同的命名空间,但这些命名控件都包括了一个相同名字的类型的时候,可以使用using关键字来创建别名,这样会使代码更简洁。注意:并不是说两个名字重复,给其中一个用了别名,另外一个就不需要用别名了,如果两个都要使用,则两个都需要用using来定义别名的
                 * using(类){} 括号中的类必须是继承了IDisposable接口才能使用否则报错
                 * 这里没有出现不同命名空间出现相同名字的类属性可以不用using(){}
                 */
                using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    long nowFileLength = fs.Length; //当前文件长度,断点前已经下载的文件长度。
                    Debug.Log(fs.Length);
                    //判断当前文件是否小于要下载文件的长度,即文件是否下载完成
                    if (nowFileLength < totalLength)
                    {
                        Debug.Log("还没下载完成");
    
                        /*使用Seek方法 可以随机读写文件
                         * Seek()  ----------有两个参数 第一参数规定文件指针以字节为单位移动的距离。第二个参数规定开始计算的位置
                         * 第二个参数SeekOrigin 有三个值:Begin  Current   End
                         * fs.Seek(8,SeekOrigin.Begin);表示 将文件指针从开头位置移动到文件的第8个字节
                         * fs.Seek(8,SeekOrigin.Current);表示 将文件指针从当前位置移动到文件的第8个字节
                         * fs.Seek(8,SeekOrigin.End);表示 将文件指针从最后位置移动到文件的第8个字节
                         */
                        fs.Seek(nowFileLength, SeekOrigin.Begin);  //从开头位置,移动到当前已下载的子节位置
    
                        UnityWebRequest uwr = UnityWebRequest.Get(url); //创建UnityWebRequest对象,将Url传入
                        uwr.SetRequestHeader("Range", "bytes=" + nowFileLength + "-" + totalLength);//修改请求头从n-m之间
                        uwr.SendWebRequest();                      //开始请求
                        if (uwr.isNetworkError || uwr.isHttpError) //如果出错
                        {
                            Debug.Log(uwr.error); //输出 错误信息
                        }
                        else
                        {
                            long index = 0;     //从该索引处继续下载
                            while (nowFileLength < totalLength) //只要下载没有完成,一直执行此循环
                            {
                                if (_isStop) 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;
                                    ProgressBar.value = (float)nowFileLength / totalLength;
                                    SliderValue.text = Math.Floor((float)nowFileLength / totalLength * 100) + "%";
                                    if (nowFileLength >= totalLength) //如果下载完成了
                                    {
                                        ProgressBar.value = 1; //改变Slider的值
                                        SliderValue.text = 100 + "%";
                                        /*这句话的作用是:如果callBack方法不为空则执行Invoke
                                         * 注意:
                                         * 1.这里的Invoke可不是Unity的Invoke延迟调用的用法,参考文章:https://blog.csdn.net/liujiejieliu1234/article/details/45312141 从文章中我们可以看到,C#中的Invoke是为了防止winform中子主线程刚开始创建对象时,子线程与主线程并发修改主线程尚未创建的对象属性。
                                         * 因为unity这里只有主线程没有用到子线程可以直接写callBack();
                                         */
                                        callBack?.Invoke();
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    
        /// <summary>
        /// 下载完成后的回调函数
        /// </summary>
        void CallBack()
        {
            Debug.Log("下载完成");
        }
    
        /// <summary>
        /// 暂停下载
        /// </summary>
        public void OnClickStop()
        {
            if (_isStop)
            {
                pauseBtn.GetComponentInChildren<Text>().text = "暂停下载";
                Debug.Log("继续下载");
                _isStop = !_isStop;
                OnClickStartDownload();
            }
            else
            {
                pauseBtn.GetComponentInChildren<Text>().text = "继续下载";
                Debug.Log("暂停下载");
                _isStop = !_isStop;
            }
        }
    }
    

    如果以上有什么不对,或者可以优化的地方欢迎大家指正,感谢。

    展开全文
  • using System; using System.Collections; using System.IO; using UnityEditor; using UnityEngine; using UnityEngine.Networking;...public class ... * UnityWebRequest支持与上传,下载及断点续传功能。
    using System;
    using System.Collections;
    using System.IO;
    using UnityEditor;
    using UnityEngine;
    using UnityEngine.Networking;
    using UnityEngine.UI;
    
    public class UnityWebRequestDemo : MonoBehaviour
    {
        /*
         * 一.概述
         * UnityWebRequest支持与上传,下载及断点续传功能。
         * UnityWebRequest由三个元素组成:
         * 1. UploadHandler 处理数据将数据上传到服务器的对象
         * 2. DownloadHandler 从服务器下载数据的对象
         * 3. UnityWebRequest 负责与Http进行通信并管理上面两个对象
         *
         * 常用的方法:
         * SendWebRequest():开始与远程服务器通信。在调用此方法之后,有必要的话UnityWebRequest将执行DNS解析,将HTTP请求发送到目标URL的远程服务器并处理服务器的响应
         * Get(url): 创建一个HTTP为传入URL的UnityWebRequest对象
         * Post(url): 向Web服务器发送表单信息
         * Put(url): 将数据上传到Web服务器
         * Abort(): 直接结束联网
         * Head(): 创建一个为传输Http头请求的UnityWebRequest对象
         * GetResponseHeader(): 返回一个字典,内容为在最新的HTTP响应中收到的所有响应头
         */
    
        /*
         * 二.构造函数
         * public UnityWebRequest();
         * public UnityWebRequest(Uri uri);
         * public UnityWebRequest(Uri uri,string method);
         * public UnityWebRequest(Uri uri,string method,Networking.DownloadHandler downloadHandler,Networking.UploadHandler uploadHandler);
         * 参数含义:
         * method:相当于方法,只有GET、POST、PUT、HEAD四种,默认为GET,一旦调用SendWebRequest(),就无法更改
         * downloadHandler:下载数据的委托方法
         * uploadHandler:上传数据的委托方法
         */
    
        private void Start()
        {
    //        Get();
    //        Post();
    //        Put();
    //        Head();
    //        GetResponseHeader();
    //        DownLoadFile();
    //        BreakpointDownload();
        }
    
        #region GET
    
        /*
         * Get方法,创建一个 UnityWebReqest对象,参数传入URL。
         */
    
        void Get()
        {
            StartCoroutine(SendRequest_Get());
        }
    
        IEnumerator SendRequest_Get()
        {
            UnityWebRequest unityWebRequest = UnityWebRequest.Get("http://www.baidu.com"); //创建UnityWebRequest对象
            yield return unityWebRequest.SendWebRequest(); //等待返回请求的信息
            if (unityWebRequest.result == UnityWebRequest.Result.ProtocolError ||
                unityWebRequest.result == UnityWebRequest.Result.ConnectionError) //如果其 请求失败,或是 网络错误
            {
                Debug.Log(unityWebRequest.error); //打印错误原因
            }
            else //请求成功
            {
                Debug.Log("Get:请求成功");
                //如果访问的链接有返回文本结果,比如json文本,则通过text获取
                string result = unityWebRequest.downloadHandler.text;
                Debug.Log(result);
                //如果访问的是资源链接,比如图片,则通过data拿到图片二进制流
                //byte[] data = uwr.downloadHandler.data;
            }
        }
    
        #endregion
    
    
        #region POST
    
        /*
         * Post方法将一个表上传到远程的服务器,一般来说我们登陆某个网站的时候会用到这个方法,我们的账号密码会以一个表单的形式传过去。
         */
    
        void Post()
        {
            StartCoroutine(SendRequest_Post());
        }
    
        IEnumerator SendRequest_Post()
        {
            WWWForm form = new WWWForm();
            //键值对
            form.AddField("key", "value");
            form.AddField("name", "Chinar");
            //请求链接,并将form对象发送到远程服务器
            UnityWebRequest webRequest = UnityWebRequest.Post("http://www.baidu.com", form);
    
            yield return webRequest.SendWebRequest();
            if (webRequest.result == UnityWebRequest.Result.ProtocolError ||
                webRequest.result == UnityWebRequest.Result.ConnectionError) //如果其 请求失败,或是 网络错误
            {
                Debug.Log(webRequest.error);
            }
            else
            {
                Debug.Log("发送成功");
            }
        }
    
        #endregion
    
        #region PUT
    
        /*
         * Put方法将数据发送到远程的服务器。
         */
    
        void Put()
        {
            StartCoroutine(SendRequest_Put());
        }
    
        IEnumerator SendRequest_Put()
        {
            byte[] myData = System.Text.Encoding.UTF8.GetBytes("Chinar的测试数据");
            using (UnityWebRequest webRequest = UnityWebRequest.Put("http://www.baidu.com", myData))
            {
                yield return webRequest.SendWebRequest();
    
                if (webRequest.result == UnityWebRequest.Result.ProtocolError ||
                    webRequest.result == UnityWebRequest.Result.ConnectionError) //如果其 请求失败,或是 网络错误
                {
                    Debug.Log(webRequest.error);
                }
                else
                {
                    Debug.Log("上传成功!");
                }
            }
        }
    
        #endregion
    
        #region HEAD
    
        void Head()
        {
            StartCoroutine(SendRequest_Head());
        }
    
        IEnumerator SendRequest_Head()
        {
            UnityWebRequest webRequest =
                UnityWebRequest.Head("http://www.chinar.xin/chinarweb/WebRequest/Get/00-效果.mp4"); //创建UnityWebRequest对象
            yield return webRequest.SendWebRequest(); //等待返回请求的信息
            if (webRequest.result == UnityWebRequest.Result.ProtocolError ||
                webRequest.result == UnityWebRequest.Result.ConnectionError) //如果其 请求失败,或是 网络错误
            {
                Debug.Log(webRequest.error); //打印错误原因
            }
            else //请求成功
            {
                Debug.Log("Head:请求成功");
            }
        }
    
        #endregion
    
        #region Abort
    
        /*
         * Abort方法会尽快结束联网,可以随时调用此方法。
         *如果 UnityWebRequest尚未完成,那么 UnityWebRequest将尽快停止上传或下载数据。 中止的 UnityWebRequests被认为遇到了系统错误 。
         *isNetworkError或isHttpError属性将返回true,error属性将为“User Aborted”。
         */
    
        #endregion
    
        #region GetResponseHeader
    
        /*
         * GetResponseHeader方法可以用来获取请求文件的长度 传入参数 "Content-Length"字符串,表示获取文件内容长度。
         */
    
        void GetResponseHeader()
        {
            StartCoroutine(SendRequest_GetResponseHeader());
        }
    
        IEnumerator SendRequest_GetResponseHeader()
        {
            UnityWebRequest
                webRequest = UnityWebRequest.Head(
                    "http://www.chinar.xin/chinarweb/WebRequest/Get/00-效果.mp4"); //创建UnityWebRequest对象
            yield return webRequest.SendWebRequest(); //等待返回请求的信息
            if (webRequest.result == UnityWebRequest.Result.ProtocolError ||
                webRequest.result == UnityWebRequest.Result.ConnectionError) //如果其 请求失败,或是 网络错误
            {
                Debug.Log(webRequest.error); //打印错误原因
            }
            else //请求成功
            {
                long totalLength = long.Parse(webRequest.GetResponseHeader("Content-Length")); //首先拿到文件的全部长度
                Debug.Log("totalLength"); //打印文件长度
            }
        }
    
        #endregion
    
    
        /*
         * -------------------------------------------常用属性-------------------------------------------
         * 属性                                      类型            含义
         * timeout                                   int             等待时间(秒)超过此数值是 UnityWebReqest的尝试连接将终止
         * UnityWebRequest.Result.ProtocolError      bool            HTTP响应出现出现错误
         * UnityWebRequest.Result.ConnectionError    bool            系统出现错误
         * error                                     string          描述 UnityWebRequest对象在处理HTTP请求或响应时遇到的任何系统错误
         * downloadProgress                          float           表示从服务器下载数据的进度
         * uploadProgress                            float           表示从服务器上传数据的进度
         * isDone                                    bool            是否完成与远程服务器的通信
         */
    
    
        #region DownloadFill
    
        public Slider ProgressBar; //进度条
        public Text SliderValue; //滑动条值
        public Button startBtn; //开始按钮
    
        void DownLoadFile()
        {
            //初始化进度条和文本框
            ProgressBar.value = 0;
            SliderValue.text = "0.0%";
            startBtn.onClick.AddListener(OnClickStartDownload);
        }
    
        /// <summary>
        /// 回调函数:开始下载
        /// </summary>
        public void OnClickStartDownload()
        {
            StartCoroutine(DownloadFile());
        }
    
        /// <summary>
        /// 协程:下载文件
        /// </summary>
        IEnumerator DownloadFile()
        {
            UnityWebRequest uwr =
                UnityWebRequest.Get(
                    "file:///C:/Users/Administrator/Music/VipSongsDownload/全昭弥 (전소미) - What You Waiting For.mflac"); //创建UnityWebRequest对象,将Url传入
            uwr.SendWebRequest(); //开始请求
            if (uwr.isNetworkError || uwr.isHttpError) //如果出错
            {
                Debug.Log(uwr.error); //输出 错误信息
            }
            else
            {
                while (!uwr.isDone) //只要下载没有完成,一直执行此循环
                {
                    ProgressBar.value = uwr.downloadProgress; //展示下载进度
                    SliderValue.text = Math.Floor(uwr.downloadProgress * 100) + "%";
                    yield return 0;
                }
    
                if (uwr.isDone) //如果下载完成了
                {
                    print("完成");
                    ProgressBar.value = 1; //改变Slider的值
                    SliderValue.text = 100 + "%";
                }
    
                byte[] results = uwr.downloadHandler.data;
                // 注意真机上要用Application.persistentDataPath
                CreateFile(Application.streamingAssetsPath + "/MP4/test.mp4", results,
                    uwr.downloadHandler.data.Length); //事先要在StreamingAssets创建一个MP4文件夹
                AssetDatabase.Refresh(); //Asset资源刷新
            }
        }
    
        /// <summary>
        /// 这是一个创建文件的方法
        /// </summary>
        /// <param name="path">保存文件的路径</param>
        /// <param name="bytes">文件的字节数组</param>
        /// <param name="length">数据长度</param>
        void CreateFile(string path, byte[] bytes, int length)
        {
            Stream swream;
            FileInfo file = new FileInfo(path);
            if (!file.Exists)
            {
                swream = file.Create();
            }
            else
            {
                return;
            }
    
            swream.Write(bytes, 0, length);
            swream.Close();
            swream.Dispose();
        }
    
        #endregion
    
        #region BreakpointDownload 断点续传
    
        private bool _isStop; //是否暂停
        public Slider _ProgressBar; //进度条
        public Text _SliderValue; //滑动条值
        public Button _startBtn; //开始按钮
        public Button pauseBtn; //暂停按钮
        private string Url = "file:///C:/Users/Administrator/Music/VipSongsDownload/全昭弥 (전소미) - What You Waiting For.mflac";
    
        void BreakpointDownload()
        {
            //初始化进度条和文本框
            _ProgressBar.value = 0;
            _SliderValue.text = "0.0%";
            startBtn.onClick.AddListener(SatrtDownload);
            pauseBtn.onClick.AddListener(OnClickStop);
        }
    
        /// <summary>
        /// 回调函数:开始下载
        /// </summary>
        public void SatrtDownload()
        {
            // 注意真机上要用Application.persistentDataPath
            StartCoroutine(DownloadFile(Url, Application.streamingAssetsPath + "/MP4/test.mp4", CallBack));
        }
    
    
        /// <summary>
        /// 协程:下载文件
        /// </summary>
        /// <param name="url">请求的Web地址</param>
        /// <param name="filePath">文件保存路径</param>
        /// <param name="callBack">下载完成的回调函数</param>
        /// <returns></returns>
        IEnumerator DownloadFile(string url, string filePath, Action callBack)
        {
            UnityWebRequest huwr = UnityWebRequest.Head(url); //Head方法可以获取到文件的全部长度
            yield return huwr.SendWebRequest();
            if (huwr.isNetworkError || huwr.isHttpError) //如果出错
            {
                Debug.Log(huwr.error); //输出 错误信息
            }
            else
            {
                long totalLength = long.Parse(huwr.GetResponseHeader("Content-Length")); //首先拿到文件的全部长度
                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; //当前文件长度
                    Debug.Log(fs.Length);
                    if (nowFileLength < totalLength)
                    {
                        Debug.Log("还没下载完成");
                        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) //只要下载没有完成,一直执行此循环
                            {
                                if (_isStop) 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;
                                    ProgressBar.value = (float) nowFileLength / totalLength;
                                    SliderValue.text = Math.Floor((float) nowFileLength / totalLength * 100) + "%";
                                    if (nowFileLength >= totalLength) //如果下载完成了
                                    {
                                        ProgressBar.value = 1; //改变Slider的值
                                        SliderValue.text = 100 + "%";
                                        callBack?.Invoke();
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    
        /// <summary>
        /// 下载完成后的回调函数
        /// </summary>
        void CallBack()
        {
            Debug.Log("下载完成");
        }
    
        /// <summary>
        /// 暂停下载
        /// </summary>
        public void OnClickStop()
        {
            if (_isStop)
            {
                pauseBtn.GetComponentInChildren<Text>().text = "暂停下载";
                Debug.Log("继续下载");
                _isStop = !_isStop;
                OnClickStartDownload();
            }
            else
            {
                pauseBtn.GetComponentInChildren<Text>().text = "继续下载";
                Debug.Log("暂停下载");
                _isStop = !_isStop;
            }
        }
    
        #endregion
    }
    

    参考了 林新发 的文章,把内容都写入代码中方便查看和加深印象。
    原文链接:https://linxinfa.blog.csdn.net/article/details/94436027

    展开全文
  • UnityWebRequest 异步下载

    2021-12-10 13:34:10
    UnityWebRequest的异步写法 using System; using System.Threading; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Networking; public class Example : MonoBehaviour { /// <summary&...

    UnityWebRequest的异步写法

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using UnityEngine;
    using UnityEngine.Networking;
    
    public class Example : MonoBehaviour
    {
        /// <summary>
        /// 任务取消源
        /// </summary>
        CancellationTokenSource ts = new CancellationTokenSource();
        void Start()
        {
            SynchronizationContext.SetSynchronizationContext(SynchronizationContext.Current);
            Test();
        }
    
        private void OnDestroy()
        {
            // 取消访问
            ts.Cancel();
        }
    
        async void Test()
        {
            string url = "http://www.baidu.com";
            try
            {
                // 更新进度
                var progress = new Progress<float>(v =>
                {
                    Debug.Log(v);
                });
                // ts.Token 创建取消通知
                // 访问链接
                var www = await RequestHelper.GetAsync(url, null, progress, ts.Token, 5000);
                // 假如取消了访问,因为异步内部抛出了AggregateException异常,下面语句不再执行
                Debug.Log(www.downloadHandler.text.Length);
            }
            catch(Exception ex)
            {
                Debug.LogError(ex);
            }
        }
    }
    
    public class RequestHelper
    {
        public static async Task<UnityWebRequest> GetAsync(string url, int timeout = 10000)
        {
            var request = UnityGetRequest.Create(url, null, timeout);
            while (!request.isDone)
            {
                await Task.Delay(16);
            }
            return request.unityWebRequest;
        }
        public static async Task<UnityWebRequest> GetAsync(string url, IProgress<float> progress, int timeout = 10000)
        {
            var request = UnityGetRequest.Create(url, null, timeout);
    
            while (!request.isDone)
            {
                progress.Report(request.Progress);
                await Task.Delay(16);
            }
            return request.unityWebRequest;
        }
        public static async Task<UnityWebRequest> GetAsync(string url, IProgress<float> progress, CancellationToken token, int timeout = 10000)
        {
            var request = UnityGetRequest.Create(url, null, timeout);
    
            while (!request.isDone)
            {
                if (token.IsCancellationRequested)
                {
                    token.ThrowIfCancellationRequested();
                }
                progress.Report(request.Progress);
                await Task.Delay(16);
            }
            return request.unityWebRequest;
        }
        public static async Task<UnityWebRequest> GetAsync(string url, WWWForm formData,  IProgress<float> progress, CancellationToken token, int timeout=10000)
        {
            var request = UnityGetRequest.Create(url, formData, timeout);
    
            while (!request.isDone)
            {
                if (token.IsCancellationRequested)
                {
                    token.ThrowIfCancellationRequested();
                }
                progress.Report(request.Progress);
                await Task.Delay(16);
            }
            return request.unityWebRequest;
        }
    
        public static async Task<UnityWebRequest> PostAsync(string url, WWWForm formData, IProgress<float> progress, CancellationToken token, int timeout = 10000)
        {
            var request = UnityPostRequest.Create(url, formData, timeout);
    
            while (!request.isDone)
            {
                if (token.IsCancellationRequested)
                {
                    token.ThrowIfCancellationRequested();
                }
                progress.Report(request.Progress);
                await Task.Delay(16);
            }
            return request.unityWebRequest;
        }
    
        interface IUnityWebRequest
        {
            bool isDone { get; }
            float Progress { get; }
            UnityWebRequest unityWebRequest { get; }
        }
        class UnityGetRequest : IUnityWebRequest
        {
            UnityWebRequest request;
            bool IUnityWebRequest.isDone => request.isDone;
    
            float IUnityWebRequest.Progress => request.downloadProgress;
    
            UnityWebRequest IUnityWebRequest.unityWebRequest => request;
    
            public static IUnityWebRequest Create(string url, WWWForm formData, int timeout)
            {
                UnityGetRequest unityGetRequest = new UnityGetRequest();
                unityGetRequest.request = UnityWebRequest.Get(url);
                unityGetRequest.request.timeout = timeout;
                if (formData != null)
                {
                    foreach (var header in formData.headers)
                    {
                        unityGetRequest.request.SetRequestHeader(header.Key, header.Value);
                    }
                }
                unityGetRequest.request.SendWebRequest();
                return unityGetRequest;
            }
        }
        class UnityPostRequest : IUnityWebRequest
        {
            UnityWebRequest request;
    
            bool IUnityWebRequest.isDone => request.isDone;
    
            float IUnityWebRequest.Progress => request.uploadProgress;
    
            UnityWebRequest IUnityWebRequest.unityWebRequest => request;
    
            public static IUnityWebRequest Create(string url, WWWForm formData, int timeout)
            {
                UnityPostRequest unityPostRequest = new UnityPostRequest();
                unityPostRequest.request = UnityWebRequest.Post(url, formData);
                unityPostRequest.request.timeout = timeout;
                unityPostRequest.request.SendWebRequest();
                return unityPostRequest;
            }
        }
    }
    
    展开全文
  • 但是我就纳闷了,为什么不能直接用 UnityWebRequest.Post 呢?经过尝试得到了本篇文章里提及的后端的报错。而我之前一直没注意到 UnityWebRequest.Post(string uri, string postData) 这个方法在内部居然会先进行 ...
  • Unity UnityWebRequest Get与Post应用

    千次阅读 2020-11-13 22:24:40
    } IEnumerator _PostRaw(string url,HttpHelperPostGetCallbacks callback, JsonData fields,JsonData header,int timeout = 5) { using (UnityWebRequest webRequest = UnityWebRequest.Post(url,"POST")) { //...
  • 卸载,控制同时加载数量 1、封装一个LoadingTexture,包含开始下载,中断,callback,释放,是否正在下载,是否开始下载(如果不需要控制下载数量,此属性可不要) class LoadingTexture { private UnityWebRequest ...
  • UnityWebRequest替代WWW

    2020-07-30 11:22:58
    转载:... Head方法 Head方法与Get方法用法一致,都是传入一个Url /// /// 开启一个协程,发送请求 /// /// IEnumerator SendRequest1() { UnityWebRequest uwr = UnityWebRequest.Head(...
  • Unity UnityWebRequest 学习

    2020-05-18 18:59:46
    记录一下UnityWebRequest学习 UnityWebRequest对象用于与web服务器通信。 unitywebre任务处理与web服务器的HTTP通信流。其他对象——特别是下载处理程序和UploadHandler——分别管理下载和上传数据。 为方便起见,...
  • 博客原文 Chinar blog :www.chinar.xin UnityWebRequest 本文提供全流程,中文翻译。 Chinar 的初衷是将一

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 40,172
精华内容 16,068
关键字:

webrequest