Chinar blog :www.chinar.xin
Chinar 的初衷是将一种简单的生活方式带给世人 使有限时间 具备无限可能 |
助力快速完成 UnityWebRequest 的认识和使用 为新手节省宝贵的时间,避免采坑! |
UnityWebReqest
是Unity提供的一种新的网络请求方式
UnityWebReqest
实例化出来的对象将用于与Web服务器的通信
它将替代已被弃用的WWW
网络请求方式
UnityWebRequest
由三个元素组成:
1.UploadHandler
处理数据将数据上传到服务器的对象
2.DownloadHandler
从服务器下载数据的对象
3.UnityWebRequest
负责与HTTP 通信并管理上面两个对象。
UnityWebRequest
支持与上传,下载及断点续传功能,十分好用
几个常用方法:
方法 | 作用 |
---|---|
SendWebRequest() |
开始与远程服务器通信。在调用此方法之后,有必要的话UnityWebRequest 将执行DNS解析,将HTTP请求发送到目标URL的远程服务器并处理服务器的响应。 |
Get(url) |
创建一个http为传入ur l的 UnityWebRequest 对象 |
Post(url) |
向Web服务器发送表单信息 |
Put(url) |
将数据上传到 Web 服务器 |
Abort() |
直接结束联网 |
Head() |
创建一个为传输HTTP头请求的 UnityWebRequest 对象 |
GetResponseHeader() |
返回一个字典,内容为在最新的 HTTP 响应中收到的所有响应头 |
除了构造函数外,UnityWebReqest
提供了几个公有的静态方法,我们可以使用它们进行 UnityWebReqest
构造
Unity几乎将所有我们需要初始化的数据,封装为构造函数,并进行重载。
我们通过这些构造函数可以方便的初始化一个UnityWebReqest
对象。
首先看其中两个构造函数:
public UnityWebRequest(); public UnityWebRequest(Uri uri)
;
参数Uri
其实就是一个Url
对象
同样,如果嫌麻烦,可以将uri直接改为 string
传入进去
我们创建一个脚本,在Start方法中写下如下代码
void Start()
{
//首先初始化一个 UnityWebRequest 对象,将我们想连接的地址传入
//第一种:直接传string
UnityWebRequest uwr = new UnityWebRequest("http://www.baidu.com");
//第二种:Uri
Uri uri = new Uri("http://www.baidu.com"); //Uri 是 System 命名空间下的一个类,注意引用该命名空间
UnityWebRequest uwr2 = new UnityWebRequest(uri); //创建UnityWebRequest对象
print(uwr.url); //打印一下url属性
}
下面看另外两种构造函数
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 |
上传数据的委托方法 |
运行查看一下打印结果
看到 UnityWebReqest
该对象,已经将该地址保存
那如何向一个URL地址对应的服务器发送请求呢?
我们来使用协程,完成网络请求,并等待返回信息
SendWebRequest
会按照我们指定的地址,去请求并处理远程服务器的响应
Uri 是 System 命名空间下的一个类,注意引用该命名空间!
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
///
/// 网络请求测试
///
public class ChinarWebRequest : MonoBehaviour
{
void Start()
{
StartCoroutine(SendRequest());
}
///
/// 开启一个协程,发送请求
///
///
IEnumerator SendRequest()
{
Uri uri = new Uri("http://www.baidu.com"); //Uri 是 System 命名空间下的一个类,注意引用该命名空间
UnityWebRequest uwr = new UnityWebRequest(uri); //创建UnityWebRequest对象
yield return uwr.SendWebRequest(); //等待返回请求的信息
if (uwr.isHttpError || uwr.isNetworkError) //如果其 请求失败,或是 网络错误
{
print(uwr.error); //打印错误原因
}
else //请求成功
{
print("请求成功");
}
}
}
运行看打印结果
当我们断开网络后:连接失败,不能解析远程主机
SendWebRequest
这种方法只能在任何给定的UnityWebRequest
对象中调用一次。一旦这个方法被调用,您就不能更改UnityWebRequest
的任何属性。这个方法返回一个
WebRequestAsyncOperation
(异步操作对象)。在一个协程中产生
WebRequestAsyncOperation
(异步操作对象)会导致协程暂停,直到UnityWebRequest
遇到系统错误或完成通信
Get
方法为创建一个http为传入url的 UnityWebReqest
对象
将代码中new UnityWebRequest
改为UnityWebRequest.Get()
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
///
/// 网络请求测试
///
public class ChinarWebRequest : MonoBehaviour
{
void Start()
{
StartCoroutine(SendRequest());
}
///
/// 开启一个协程,发送请求
///
///
IEnumerator SendRequest()
{
Uri uri = new Uri("http://www.baidu.com"); //Uri 是 System 命名空间下的一个类,注意引用该命名空间
UnityWebRequest uwr = new UnityWebRequest(uri); //创建UnityWebRequest对象
yield return uwr.SendWebRequest(); //等待返回请求的信息
if (uwr.isHttpError || uwr.isNetworkError) //如果其 请求失败,或是 网络错误
{
print(uwr.error); //打印错误原因
}
else //请求成功
{
print("UnityWebRequest:请求成功");
print(uwr.downloadedBytes);
}
print("--------------------");
yield return SendRequest1(); //等待返回请求的信息
}
///
/// 开启一个协程,发送请求
///
///
IEnumerator SendRequest1()
{
UnityWebRequest uwr = UnityWebRequest.Get("http://www.baidu.com"); //创建UnityWebRequest对象
yield return uwr.SendWebRequest(); //等待返回请求的信息
if (uwr.isHttpError || uwr.isNetworkError) //如果其 请求失败,或是 网络错误
{
print(uwr.error); //打印错误原因
}
else //请求成功
{
print("Get:请求成功");
print(uwr.downloadedBytes);
}
}
}
使用
Get
方法创建UnityWebRequest
对象与使用只传入Url
构造函数的区别: 使用Get方
法时会默认的给对象创建一个DownloadHander与UploadHandler对象。 而使用只传入Url
的构造函数创建只是给UnityWebRequest
对象赋值了一个Url
,调用downloadHander.txt时会报错
Post
方法将一个表上传到远程的服务器,一般来说我们登陆某个网站的时候会用到这个方法,我们的账号密码会以一个表单的形式传过去,表单是什么?请参考WWWForm类
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
///
/// 网络请求测试
///
public class ChinarWebRequest : MonoBehaviour
{
void Start()
{
StartCoroutine(Post());
}
///
/// 开启一个协程,发送请求
///
///
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("发送成功");
}
}
}
Put
方法将数据发送到远程的服务器
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
///
/// 网络请求测试
///
public class ChinarWebRequest : MonoBehaviour
{
void Start()
{
StartCoroutine(Upload());
}
///
/// 开启协程
///
///
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("上传成功!");
}
}
}
}
Abort
方法会尽快结束联网,可以随时调用此方法。 如果UnityWebRequest
尚未完成,那么UnityWebRequest
将尽快停止上传或下载数据。 中止的UnityWebRequests
被认为遇到了系统错误。
isNetworkError
或isHttpError
属性将返回true,error
属性将为“User Aborted”
。
如果在调用 SendWebRequest
之前调用此方法,则 UnityWebRequest
将在调用SendWebRequest
后立即中止联网。在此 UnityWebRequest
遇到其他错误或已成功完成与远程服务器的通信后,那么此方法调用无效。
Head方法与Get方法用法一致,都是传入一个Url
///
/// 开启一个协程,发送请求
///
///
IEnumerator SendRequest1()
{
UnityWebRequest uwr = UnityWebRequest.Head("http://www.chinar.xin/chinarweb/WebRequest/Get/00-效果.mp4"); //创建UnityWebRequest对象
yield return uwr.SendWebRequest(); //等待返回请求的信息
if (uwr.isHttpError || uwr.isNetworkError) //如果其 请求失败,或是 网络错误
{
print(uwr.error); //打印错误原因
}
else //请求成功
{
print("Head:请求成功");
}
}
GetResponseHeader
方法可以用来获取请求文件的长度 传入参数"Content-Length"
字符串,表示获取文件内容长度。
///
/// 开启一个协程,发送请求
///
///
IEnumerator SendRequest1()
{
UnityWebRequest uwr = UnityWebRequest.Head("http://www.chinar.xin/chinarweb/WebRequest/Get/00-效果.mp4"); //创建UnityWebRequest对象
yield return uwr.SendWebRequest(); //等待返回请求的信息
if (uwr.isHttpError || uwr.isNetworkError) //如果其 请求失败,或是 网络错误
{
print(uwr.error); //打印错误原因
}
else //请求成功
{
long totalLength = long.Parse(huwr.GetResponseHeader("Content-Length")); //首先拿到文件的全部长度
print("totalLength");//打印文件长度
}
}
几个常用属性:
属性 | 类型 | 含义 |
---|---|---|
timeout |
int | 等待时间(秒)超过此数值是 UnityWebReqest 的尝试连接将终止 |
isHttpError |
bool | http响应出现出现错误 |
isNetworkError |
bool | 系统出现错误 |
error |
string | 描述 UnityWebRequest 对象在处理HTTP请求或响应时遇到的任何系统 错误 |
downloadProgress |
float | 表示从服务器下载数据的进度 |
uploadProgress |
float | 表示从服务器上传数据的进度 |
isDone |
bool | 是否完成与远程服务器的通信 |
UnityWebRequest
对象将在timeout
秒后尝试终止 发生超时时,错误返回“Request
timeout”(请求超时)。timeout
设置为0且此属性默认为时,不应用超时。
属性为只读 表示HTTP响应是否出现错误
只有响应代码大于400的时候才会返回 True
,比如常见的404
UnityWebRequest
对象遇到系统错误后返回true
系统错误的示例包括无法解析DNS条目,套接字错误或超出重定向限制。当此属性返回true时,error
属性将包含描述错误的原因。
错误类型的服务器返回代码(例如404 / Not Found和500 / Internal Server Error)反映在isHttpError
属性中
字符串类型,只读,返回UnityWebRequest对象在处理HTTP请求或响应时遇到的任何系统错误 如果
UnityWebRequest
未遇到系统错误,则此属性将返回
null
。系统错误的示例包括套接字错误,解析DNS条目的错误或超出重定向限制
来自服务器的错误类型返回码(例如404 / File Not Found或500 / Internal Server Error)不被视为系统错误。
float类型,只读,返回一个0.0~1.0的值,指示从服务器下载数据的进度。
如果UnityWebRequest
已成功完成链接或遇到系统错误,则此属性将返回1.
如果UnityWebRequest
仍在与远程服务器通信,并且downloadHandler
为null,则此属性将返回0.5。
如果尚未调用SendWebRequest()
,则此属性将返回-1。
仅当服务器的响应包含 Content-Length
标头并且 UnityWebRequest
具有附加到 downloadHandler
属性的 DownloadHandler对象
时,此属性才有效。
与downloadProgress相同,float类型,只读,返回一个0.0~1.0的值,指示从服务器上传数据的进度。
如果UnityWebRequest
已成功完成链接或遇到系统错误,则此属性将返回1.
如果UnityWebRequest
仍在与远程服务器通信,并且downloadHandler
为null,则此属性将返回0.5。
如果尚未调用SendWebRequest()
,则此属性将返回-1。
只读,
UnityWebRequest
完成与远程服务器通信后或遇到系统错误时返回true 。
DownloadHandler
(如果有)的所有下载处理将在此属性返回true之前完成。我们可以用它来判断下载是否完成
例子中需要一个Web服务器,没有的同学不要担心,Chinar为大家提供一个测试的Web服务器,地址在例子中
我们将下面的图片放到设置好的Web服务器目录下面,命名为Chinar.png
创建一个脚本:
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
///
/// 02-ChinarDownLoadTexture:
/// 用来测试服务器上传
///
public class ChinarDownLoadTexture : MonoBehaviour
{
public string url = "http://www.chinar.xin/chinarweb/WebRequest/Get/Chinar.png";
public Image downImage;
void Start()
{
StartCoroutine(GetTexture(url));
}
///
/// 请求图片
///
/// 图片地址,like 'http://www.chinar.xin/chinarweb/WebRequest/Get/Chinar.png '
IEnumerator GetTexture(string url)
{
UnityWebRequest uwr = UnityWebRequest.Get(url);
DownloadHandlerTexture downloadTexture = new DownloadHandlerTexture(true);
uwr.downloadHandler = downloadTexture;
yield return uwr.SendWebRequest();
if (uwr.isNetworkError || uwr.isHttpError)
{
print(uwr.error);
}
else
{
Texture2D t = downloadTexture.texture;
downImage.sprite = Sprite.Create(t, new Rect(0, 0, t.width, t.height), Vector2.one);
}
}
}
using System;
using System.Collections;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
///
///
///
public class ChinarDownLoadFile : MonoBehaviour
{
public Slider ProgressBar; //进度条
public Text SliderValue; //滑动条值
private Button startBtn; //开始按钮
void Start()
{
//初始化进度条和文本框
ProgressBar.value = 0;
SliderValue.text = "0.0%";
startBtn = GameObject.Find("Start Button").GetComponent<Button>();
startBtn.onClick.AddListener(OnClickStartDownload);
}
///
/// 回调函数:开始下载
///
public void OnClickStartDownload()
{
StartCoroutine(DownloadFile());
}
///
/// 协程:下载文件
///
IEnumerator DownloadFile()
{
UnityWebRequest uwr = UnityWebRequest.Get("http://www.chinar.xin/chinarweb/WebRequest/Get/00-效果.mp4"); //创建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;
CreateFile(Application.streamingAssetsPath + "/MP4" + "/00-效果.mp4", results, uwr.downloadHandler.data.Length);
AssetDatabase.Refresh(); //刷新一下
}
}
///
/// 这是一个创建文件的方法
///
/// 保存文件的路径
/// 文件的字节数组
/// 数据长度
void CreateFile(string path, byte[] bytes, int length)
{
Stream sw;
FileInfo file = new FileInfo(path);
if (!file.Exists)
{
sw = file.Create();
}
else
{
return;
}
sw.Write(bytes, 0, length);
sw.Close();
sw.Dispose();
}
}
首先看UI界面,界面仅增加了一个暂停下载的按钮
创建脚本并写下如下代码:
// ========================================================
// 描述:基于UnityWebReqest的断点续传
// 作者:Chinar
// 创建时间:2019-04-22 17:59:20
// 版 本:1.0
// ========================================================
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; //滑动条值
private Button startBtn; //开始按钮
private Button pauseBtn; //暂停按钮
public string Url = "http://www.chinar.xin/chinarweb/WebRequest/Get/00-效果.mp4";
///
/// 初始化UI界面及给按钮绑定方法
///
void Start()
{
//初始化进度条和文本框
ProgressBar.value = 0;
SliderValue.text = "0.0%";
startBtn = GameObject.Find("Start Button").GetComponent<Button>();
startBtn.onClick.AddListener(OnClickStartDownload);
pauseBtn = GameObject.Find("Pause Button").GetComponent<Button>();
pauseBtn.onClick.AddListener(OnClickStop);
}
///
/// 回调函数:开始下载
///
public void OnClickStartDownload()
{
StartCoroutine(DownloadFile(Url, Application.streamingAssetsPath + "/MP4/00-效果.mp4", CallBack));
}
///
/// 协程:下载文件
///
/// 请求的Web地址
/// 文件保存路径
/// 下载完成的回调函数
///
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; //当前文件长度
print(fs.Length);
if (nowFileLength < totalLength)
{
print("还没下载完成");
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 (!uwr.isDone) //只要下载没有完成,一直执行此循环
{
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();
}
}
}
}
}
}
}
}
///
/// 下载完成后的回调函数
///
void CallBack()
{
print("下载完成");
}
///
/// 暂停下载
///
public void OnClickStop()
{
if (_isStop)
{
pauseBtn.GetComponentInChildren<Text>().text = "暂停下载";
print("继续下载");
_isStop = !_isStop;
OnClickStartDownload();
}
else
{
pauseBtn.GetComponentInChildren<Text>().text = "继续下载";
print("暂停下载");
_isStop = !_isStop;
}
}
}
项目文件为 unitypackage 文件包:
Chinar 提供一站式《零》基础教程 使有限时间 具备无限可能! |
Chinar 知你所想,予你所求!( Chinar Blog )
本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究
对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: [email protected]
对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址