[专栏精选]UnityWebRequest详解

本文节选自洪流学堂公众号技术专栏《大话Unity2019》,未经允许不可转载。

洪流学堂公众号回复专栏,查看更多专栏文章。


洪流学堂,让你快人几步!你好,我是你的技术探路者郑洪智,你可以叫我大智(vx: zhz11235)。。

大智:“昨天我们初步了解了UnityWebRequest是做什么用的以及如何使用,今天我们来仔细看一下昨天代码中的几个部分。”

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

public class GetFileByWebRequest : MonoBehaviour
{
    IEnumerator Start()
    {
        var uri = new System.Uri(Path.Combine(Application.streamingAssetsPath, "data.json"));
        var request = UnityWebRequest.Get(uri.AbsoluteUri);
        yield return request.SendWebRequest();

        if (request.isNetworkError || request.isNetworkError)
        {
            Debug.Log(request.error);
        }
        else
        {
            Debug.Log(request.downloadHandler.text);
        }
    }
}

我们从上到下来分析这几行代码。

Uri类

首先我们用到了System.Uri这个类,这个类可以帮助我们更好的构造uri,特别是在请求本地的file文件时。在请求本地文件时,不同的平台使用的Uri略有不同。

如果不使用Uri类时,各个平台所需要的Uri的字符串示例如下:

  • Windows平台 file:///D:/DATA/StreamingAssets/data.json
  • WebGl平台 http://localhost/StreamingAssets/data.json
  • Android平台 jar:file:///data/app/xxx!/assets/data.json
  • iOS平台 Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data/Raw

使用Uri类之后,就可以自动帮我们拼接好这些Uri的字符串,一定要记得:
var uri = new System.Uri(Path.Combine(Application.streamingAssetsPath, "data.json"));

UnityWebRequest

有了Uri以后呢,我们就可以使用UnityWebRequest来进行请求了。

虽然这个叫做WebRequest,但是要记住还可以请求本地的文件哦。

UnityWebRequest详解

UnityWebRequest封装了网络请求,支持http、https、file、和匿名ftp协议的请求以及处理。

这个类替代了WWW类,相对WWW类使用起来更复杂一些,但是功能和性能也更强大了。

UnityWebRequest类将一个请求分解为了3部分:

  • 提供请求时的输出,传输给服务器
  • 从服务器接收数据
  • 控制HTTP的请求流程

UnityWebRequest 由三个元素组成。

  • UploadHandler 处理数据 将数据发送到服务器 的对象
  • DownloadHandler 从服务器接收数据 的对象
  • UnityWebRequest 负责 HTTP 通信流量控制来管理上面两个对象的对象。

来说明这些对象之间的关系,如下所示。

流程图示

对于一次请求,通常的代码流程是:

  • 创建一个UnityWebRequest对象
  • 配置UnityWebRequest对象
    • 设置请求的header
    • 设置HTTP的方法(比如GET,POST,HEAD等,自定义HTTP方法除了Android平台,其他平台也都支持)
  • (可选)创建一个UploadHandler附加到这个UnityWebRequest对象上面
    • 提供上传的数据
    • 提供上传的HTTP表单
  • (可选)创建一个DownloadHandler附加到这个UnityWebRequest对象上面,如果需要获取返回数据一定要创建
  • 发送Send这个请求
    • 如果是在一个协程里,可以使用yield来返回SendWebRequest(),用于等待请求完成。需要注意的是:如果你之前习惯使用www,一定要注意这个UnityWebRequest在调用SendWebRequest()方法之后才会真正执行请求。
  • (可选)从DownloadHandler里面读取接收到的数据
  • (可选)从UnityWebRequest对象读取error信息、HTTP状态码、相应头等信息。

UnityWebRequest捷径

小新:“这个UnityWebRequest有点太复杂了吧?没有简单的方法么?”
大智:“这个当然是有的,下面我们来看看之前代码中使用到的Get方法。”

使用Get获取数据

获取简单的文本或者二进制数据,可以使用UnityWebRequest.Get方法。这个方法的参数非常简单,只需要传入Uri即可,和之前的WWW类很类似,可以替代WWW类使用:

// 被抛弃的WWW
WWW myWww = new WWW("http://www.myserver.com/foo.txt");
// 使用起来很类似
UnityWebRequest myWr = UnityWebRequest.Get("http://www.myserver.com/foo.txt");

一般使用的方法如下:

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
 
public class MyBehaviour : MonoBehaviour {
    void Start() {
        StartCoroutine(GetText());
    }
 
    IEnumerator GetText() {
        UnityWebRequest www = UnityWebRequest.Get("http://www.my-server.com");
        yield return www.SendWebRequest();
 
        if(www.isNetworkError || www.isHttpError) {
            Debug.Log(www.error);
        }
        else {
            // Show results as text
            Debug.Log(www.downloadHandler.text);
 
            // Or retrieve results as binary data
            byte[] results = www.downloadHandler.data;
        }
    }
}

结合协程使用(Coroutine)

之前在69节学习过使用协程,但是这里你会发现使用的方法不太一样了,这里使用的是yield return request.SendWebRequest()

为什么可以这么写呢?

我可以先告诉你作用是什么:那就是可以等待请求完成后才继续执行。

之前我们学协程的时候使用过

yield return new WaitForSeconds(3);

也就是3秒后才继续执行。

在这里呢,UnityWebRequest的请求同样可以通过协程的yield return来等待请求执行完毕,但是不会阻塞主线程。

有BOM的问题

假设我们获取到数据后要使用json解析,如果你的文件中有bom,就会出现问题。

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

[System.Serializable]
public class Npc
{
    public int Id;
    public string 名称;
    public float 血量;
    public float 攻击力;
    public float 防御力;
}

public class Npcs
{
    public Npc[] npcs;
}

public class GetFileByWebRequest : MonoBehaviour
{
    IEnumerator Start()
    {
        var uri = new System.Uri(Path.Combine(Application.streamingAssetsPath, "data.json"));
        var request = UnityWebRequest.Get(uri);
        Debug.Log(uri);
        var www = request.SendWebRequest();
        yield return www;

        if (request.isNetworkError || request.isNetworkError)
        {
            Debug.Log(request.error);
        }
        else
        {
            var jsonStr = request.downloadHandler.text;
            Debug.Log(jsonStr);
            var npcs = JsonUtility.FromJson<Npcs>(jsonStr);
            Debug.Log(npcs.npcs.Length);
        }

    }
}

你可以尝试下如下的json文件:

{
    "npcs": [
        {
            "Id": 1,
            "名称": "小猴子",
            "血量": 10,
            "攻击力": 1,
            "防御力": 1
        },
        {
            "Id": 2,
            "名称": "大猴子",
            "血量": 100,
            "攻击力": 2,
            "防御力": 2
        },
        {
            "Id": 3,
            "名称": "孙猴子",
            "血量": 999999,
            "攻击力": 9999,
            "防御力": 9999
        }
    ]
}

如果使用utf8+bom的编码方式,就会报错:

UTF-8 with BOM
报错

所以一定一定要使用无BOM的UTF8编码的文件。

总结

  • UnityWebRequest.Get方法是最简单的,可以代替www使用
  • UnityWebRequest对象需要调用SendWebRequest之后才会执行请求
  • 一定一定要使用无BOM的UTF8编码的文件

今日思考题

大智:“先试着使用上面的代码,获取之前的文件数据试一试!”
小新:“好嘞!”
大智:“收获别忘了分享出来!也别忘了分享给你学Unity的朋友,也许能够帮到他。”


洪流学堂公众号回复专栏,查看更多专栏文章。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 9,082评论 0 3
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,084评论 1 32
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,858评论 6 13
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,420评论 1 45
  • 在一个方法内部定义的变量都存储在栈中,当这个函数运行结束后,其对应的栈就会被回收,此时,在其方法体中定义的变量将不...
    Y了个J阅读 4,412评论 1 14