Unity使用UnityWebRequest实现HTTP网络连接

Unity使用UnityWebRequest实现HTTP网络连接

UnityWebRequest

Unity中UnityWebRequestWWW都可以实现HTTP请求,但UnityWebRequest是Unity新的网络请求方式,新版本已经对WWWAPI弃用了。
UnityWebRequests处理与Web服务器的HTTP通信流。 需要注意的其他对象,特别是DownloadHandlerUploadHandler,分别管理下载上传数据。
注意:一旦UnityWebRequest开始通过调用Send方法与远程服务器通信,UnityWebRequest对象上的大多数属性都无法更改。(Send方法已经过时,API提供了SendWebRequest方法)

代码

主要

直接看下方的代码:

public class UnityHttpWebRequestPost
{
    /// <summary>
    /// 访问地址
    /// </summary>
    private string m_postURL;
    private Uri m_downloadUri = null;
    private DownloadHandler m_downloadHandler = null;
    private UnityWebRequest m_downloadRequest = null;
    /// <summary>
    /// 最终的结果字符串
    /// </summary>
    private string m_result = null;
    /// <summary>
    /// 出现的错误信息
    /// </summary>
    private string m_error = null;

    public IEnumerator Network(byte[] uploadData)
    {
        if (null == m_downloadRequest || m_downloadRequest.isDone)
        {
            m_downloadHandler = new DownloadHandlerBuffer();
            m_downloadUri = new Uri(m_postURL);
            m_downloadRequest = new UnityWebRequest(m_downloadUri.AbsoluteUri, UnityWebRequest.kHttpVerbPOST)
            {
                timeout = 90000, //设置连接超时时间
                downloadHandler = m_downloadHandler
            };
        }
        UploadHandler uploader = new UploadHandlerRaw(uploadData)
        {//创建上传数据
            contentType = "application/json"//设置HTTP协议的请求头,默认的请求头HTTP服务器无法识别
        };
        m_downloadRequest.uploadHandler = uploader;
        yield return m_downloadRequest.SendWebRequest();//发送请求,并等待结果
        if (m_downloadRequest.isNetworkError || m_downloadRequest.isHttpError)
        {//判定是否出错
            m_error = m_downloadRequest.error;
            Debug.LogError(m_error);
            yield break;
        }
        m_result = m_downloadHandler.text;//获取结果
        m_downloadRequest.Abort();
    }
}

需要注意的是

  • 每个UnityWebRequest对象都只能发送一次请求,当需要再次请求是则需要再次创建;
  • 其中UnityWebRequest对象中的DownloadHandler对象(用于下载数据),亦是如此;
  • UploadHandler对象(用于上传数据),是由于每次上传的数据都会不一样的话,就需要每次都要重新新建一个对象,用于上传;
  • 最后,上传的一些设置需要与服务器的设置对其一致,例如参考链接3中对contentType的设置。

例项

下面是我在项目中要到的一个单例对象,仅供参考。其中每次请求都连续请求两次(一次Post,一次Get),是因为第一次Post请求下来的结果是一个结果地址,还需要按照这个地址再请求一次,才能得到最终的结果数据;同时,我传输的是一个图片数据

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

public class NetworkingManager : InnerClassSingleton<NetworkingManager>
{
    private NetworkingManager()
    {//初始化
        m_postURL = "http://************";
        m_ifData = new ImgFbxData();
        m_pData = new PostData
        {
            appid = "123456",
            logid = 99999999,
            format = "json",
            from = "xxxxx",
            cmdid = "123",
            clientip = "0.0.0.0"
        };
        m_downloadUri = new Uri(m_postURL);
        CreateDownloadRequest();
        CreateResultRequest();
    }

    /// <summary>
    /// 访问地址
    /// </summary>
    private readonly string m_postURL;
    private readonly ImgFbxData m_ifData = null;
    private readonly PostData m_pData = null;
    private readonly Uri m_downloadUri = null;
    private DownloadHandler m_downloadHandler = null;
    private UnityWebRequest m_downloadRequest = null;
    private DownloadHandler m_resultHandler = null;
    private UnityWebRequest m_resultRequest = null;
    /// <summary>
    /// 转化后m_downloadRequest使用的UploadHandler的数据
    /// </summary>
    private byte[] m_uploadData = null;
    /// <summary>
    /// 中间字符串,用于获取中间转化过程中的字符串
    /// </summary>
    private string m_intermediStr = null;
    /// <summary>
    /// 下载的结果URL
    /// </summary>
    private string m_downloadURL = null;
    /// <summary>
    /// 最终的结果字符串
    /// </summary>
    private string m_result = null;
    /// <summary>
    /// 出现的错误信息
    /// </summary>
    private string m_error = null;

    public string Message { get { return m_intermediStr; } }
    public string DownloadURL { get { return m_downloadURL; } }
    public string Result { get { return m_result; } }
    public string Error { get { return m_error; } }

    private void CreateDownloadRequest()
    {
        if (null == m_downloadRequest || m_downloadRequest.isDone)
        {
            m_downloadHandler = new DownloadHandlerBuffer();
            m_downloadRequest = new UnityWebRequest(m_downloadUri.AbsoluteUri, UnityWebRequest.kHttpVerbPOST)
            {
                timeout = 90000, //设置连接超时时间
                downloadHandler = m_downloadHandler
            };
        }
    }
    private void CreateResultRequest()
    {
        if (null == m_resultRequest || m_resultRequest.isDone)
        {
            m_resultHandler = new DownloadHandlerBuffer();
            m_resultRequest = new UnityWebRequest
            {
                method = UnityWebRequest.kHttpVerbGET,
                downloadHandler = m_resultHandler
            };
        }
    }

    #region  解析Download
    /// <summary>
    /// 解析Json数据
    /// </summary>
    /// <param name="bytes">源位数组</param>
    /// <param name="utf8_string">中间传唤时的utf8格式字符串</param>
    /// <returns>最后输出的Json数据</returns>
    protected JsonData GetJsonData(byte[] bytes, out string utf8_string)
    {
        utf8_string = Encoding.UTF8.GetString(bytes);//将位数组转换为UTF8格式的字符串
        return JsonMapper.ToObject(utf8_string);//使用LitJson解析字符串为JsonData类
    }
    /// <summary>
    /// 解析Download
    /// </summary>
    /// <param name="resultBytes">Download中的位数组</param>
    protected void ParseDownload(byte[] resultBytes)
    {
        m_downloadURL = null;
        JsonData receiveData = GetJsonData(resultBytes, out m_intermediStr);
        Debug.Log("请求的结果:" + m_intermediStr);
        string result = (string)receiveData["result"];
        if (result == "")
        {//判定结果是否正确
            m_error = "result is empty, ERROR.";
            Debug.LogError(m_error);
            return;
        }
        //如果正确则需要再解析一次
        byte[] resultBuffers = Convert.FromBase64String(result);
        JsonData urlData = GetJsonData(resultBuffers, out m_intermediStr);
        Debug.Log("“result”解析后的结果:" + m_intermediStr);
        m_downloadURL = (string)urlData["url"];//获得结果的URL链接
        string[] sArray = m_downloadURL.Split('.');
        if (sArray[sArray.Length - 1] != "json")
        {//判定链接是否正确
            m_downloadURL = null;
            m_error = "result is not a json, ERROR.";
            Debug.LogError(m_error);
            return;
        }
    }
    #endregion

    #region  通信
    /// <summary>
    /// 开始通信
    /// </summary>
    /// <param name="uploadData">上传的数据</param>
    /// <returns>协程</returns>
    protected IEnumerator StartNetwork(byte[] uploadData)
    {
        CreateDownloadRequest();
        UploadHandler uploader = new UploadHandlerRaw(uploadData)
        {//创建上传数据
            contentType = "application/json"//设置HTTP协议的请求头,默认的请求头HTTP服务器无法识别
        };
        m_downloadRequest.uploadHandler = uploader;
        yield return m_downloadRequest.SendWebRequest();//发送请求,并等待结果
        if (m_downloadRequest.isNetworkError || m_downloadRequest.isHttpError)
        {//判定是否出错
            m_error = m_downloadRequest.error;
            Debug.LogError(m_error);
            yield break;
        }
        ParseDownload(m_downloadRequest.downloadHandler.data);//解析结果
        if (null != m_downloadURL)
        {//解析正确
            CreateResultRequest();
            m_resultRequest.url = m_downloadURL;//根据获取的结果链接,请求最终数据
            yield return m_resultRequest.SendWebRequest();//发送请求,并等待结果
            if (m_resultRequest.isNetworkError)
            {//判定是否出错
                m_error = m_resultRequest.error;
                Debug.LogError(m_error);
                yield break;
            }
            m_result = m_resultHandler.text;//获取PTA结果
            m_resultRequest.Abort();
        }
    }
    #endregion

    #region  一种
    /// <summary>
    /// 设置图片Base64的字符串
    /// ---- 使用之前要先将图片转化成Base64的字符串
    /// </summary>
    /// <param name="pngDataBase64">Base64的字符串</param>
    public void SetImageDataBase64(string pngDataBase64)
    {
        m_ifData.image = pngDataBase64;
        //Debug.Log(pngDataBase64);
        m_pData.data = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonMapper.ToJson(m_ifData)));
        m_uploadData = Encoding.UTF8.GetBytes(JsonMapper.ToJson(m_pData));
    }
    /// <summary>
    /// 设置图片位数组
    /// </summary>
    /// <param name="pngDataBytes">图片位数组</param>
    public void SetImageDataBytes(byte[] pngDataBytes)
    {
        SetImageDataBase64(Convert.ToBase64String(pngDataBytes));//先将图片转化成Base64的字符串
    }
    /// <summary>
    /// PTA生成
    /// </summary>
    /// <returns>协程</returns>
    private IEnumerator GenerateFace()
    {
        m_result = null;
        if (null != m_uploadData)
        {
            yield return StartNetwork(m_uploadData);
            m_uploadData = null;
        }
        else
        {
            Debug.LogError("uploadData为空!");
        }
    }
    #endregion

    #region 二种
    /// <summary>
    /// PTA生成
    /// </summary>
    /// <param name="pngDataBase64">Base64的字符串</param>
    /// <returns>协程</returns>
    public IEnumerator GenerateFaceByBase64(string pngDataBase64)
    {
        SetImageDataBase64(pngDataBase64);
        yield return GenerateFace();
    }
    /// <summary>
    /// PTA生成
    /// </summary>
    /// <param name="pngDataBytes">图片位数组</param>
    /// <param name="isSave">是否保存图片</param>
    /// <returns>协程</returns>
    public IEnumerator GenerateFaceByBytes(byte[] pngDataBytes, bool isSave = false)
    {
        if (isSave)
        {//用于保存测试观察
            int hour = DateTime.Now.Hour;
            int minute = DateTime.Now.Minute;
            int second = DateTime.Now.Second;
            int year = DateTime.Now.Year;
            int month = DateTime.Now.Month;
            int day = DateTime.Now.Day;
            string name = string.Format("{0:D4}-{1:D2}-{2:D2}-{3:D2}-{4:D2}-{5:D2}", year, month, day, hour, minute, second);
#if UNITY_EDITOR
            string path = Application.dataPath + "/Editor/Texture/" + name + ".png";
#else
                string path = Application.persistentDataPath + "/" + name + ".png";
#endif
            Debug.LogError("保存图片:" + path);
            File.WriteAllBytes(path, pngDataBytes);
        }
        SetImageDataBytes(pngDataBytes);
        yield return GenerateFace();
    }
    /// <summary>
    /// PTA生成
    /// </summary>
    /// <param name="pngPath">图片路径</param>
    /// <returns>协程</returns>
    public IEnumerator GenerateFaceByPath(string pngPath)
    {
        SetImageDataBytes(File.ReadAllBytes(pngPath));
        yield return GenerateFace();
    }
    #endregion

    #region  测试
    /// <summary>
    /// 测试
    /// </summary>
    /// <returns>协程</returns>
    public IEnumerator GenerateFace_Test(bool isJson)
    {
        if (isJson)
        {
            yield return GetTestJsonData();
        }
        else
        {
            //string inputImgPath = Application.persistentDataPath + "/1.png";
            string inputImgPath = Application.dataPath + "/Assets/Texture/Test/aipe34.jpg";
            yield return GenerateFaceByPath(inputImgPath);
        }
    }

    /// <summary>
    /// 测试Json数据
    /// </summary>
    /// <returns>协程</returns>
    protected IEnumerator GetTestJsonData()
    {
        m_result = null;
        Uri uri = new Uri(Path.Combine(Application.streamingAssetsPath, "Table/test.json"));
        UnityWebRequest request = UnityWebRequest.Get(uri.AbsoluteUri);
        yield return request.SendWebRequest();
        if (request.isNetworkError)
        {
            Debug.LogError(request.error);
            yield break;
        }
        m_result = request.downloadHandler.text;
    }
    #endregion

    #region  数据类
    public class ImgFbxData
    {
        public string image { get; set; }
    }
    public class PostData
    {
        public string appid { get; set; }
        public int logid { get; set; }
        public string format { get; set; }
        public string from { get; set; }
        public string cmdid { get; set; }
        public string clientip { get; set; }
        public string data { get; set; }
    }
    #endregion
}

下面是同样功能的HttpWebResponse脚本用于与上方的UnityWebRequest进行比较。

using LitJson;
using System;
using System.IO;
using System.Net;
using System.Text;
using UnityEngine;

public class ControlTool : MonoBehaviour
{
    public class ImgFbxData
    {
        public string image { get; set; }
    }
    public class PostData
    {
        public string appid { get; set; }
        public int logid { get; set; }
        public string format { get; set; }
        public string from { get; set; }
        public string cmdid { get; set; }
        public string clientip { get; set; }
        public string data { get; set; }
    }
    
    void Update()
    {
        //图像转base64+fbx转base64,合成json测试
        if (Input.GetKeyDown(KeyCode.B))
        {
            //============================base64============================
            string inputImgPath = Application.dataPath + "/test/aipe34.jpg";

            string imgBase64 = ObjectToBase64(inputImgPath);
            Debug.Log(imgBase64);
            ImgFbxData IFdata = new ImgFbxData();
            IFdata.image = imgBase64;
            string IFdataJsonStr = JsonMapper.ToJson(IFdata);
            Debug.Log(IFdataJsonStr);

            PostData PostData = new PostData();
            PostData.appid = "123456";
            PostData.logid = 99999999;
            PostData.format = "json";
            PostData.from = "xvision";
            PostData.cmdid = "123";
            PostData.clientip = "0.0.0.0";
            byte[] b = Encoding.UTF8.GetBytes(IFdataJsonStr);
            for (int i = 0; i < b.Length; i++)
                Debug.Log(b[i]);
            PostData.data = Convert.ToBase64String(b);
            Debug.Log(PostData.data);

            string postJsonStr = JsonMapper.ToJson(PostData);
            Debug.Log(postJsonStr);
            byte[] bytes = Encoding.UTF8.GetBytes(postJsonStr);

            //==============================保存============================
            //using (StreamWriter sw = new StreamWriter(Application.dataPath + "/test/base64Upload.txt"))
            //{
            //    sw.WriteLine(postJsonStr);
            //}

            //============================HTTP发送============================
            string postURL = "http://10.64.38.233:8189/pta/skeleton";
            HttpWebRequest request;//声明一个HttpWebRequest请求
            Stream reqstream;//获取一个请求流

            request = (HttpWebRequest)WebRequest.Create(postURL);//声明一个HttpWebRequest请求
            request.Method = "POST";
            request.KeepAlive = true;
            request.ContentLength = bytes.Length;
            request.ContentType = "application/json";
            //Stream
            reqstream = request.GetRequestStream();//发送post的请求,获取请求流
            reqstream.Write(bytes, 0, bytes.Length);//将参数字节数组写入到请求流里
            reqstream.Close();
            request.Timeout = 90000;//设置连接超时时间

            //============================HTTP接收============================
            HttpWebResponse response; //接收返回来的数据
            Stream streamReceive;//获取响应流

            //接收返回来的数据
            //HttpWebResponse
            response = (HttpWebResponse)request.GetResponse();//执行请求,获取响应对象
            //Stream 
            streamReceive = response.GetResponseStream();//获取响应流
            Encoding encoding = Encoding.UTF8;
            StreamReader streamReader = new StreamReader(streamReceive, encoding);//创建流读取对象
            string strResult = streamReader.ReadToEnd();//读取响应流
            streamReceive.Close();
            streamReader.Dispose();

            //============================解析Json============================
            JsonData receiveData = JsonMapper.ToObject(strResult);
            string result = (string)receiveData["result"];
            if (result == "")
            {
                Debug.Log("result is empty, ERROR.");
                return;
            }
            byte[] buffers = Convert.FromBase64String(result);
            string receiveJsonStr = Encoding.UTF8.GetString(buffers);
            JsonData data = JsonMapper.ToObject(receiveJsonStr);
            string fbxURL = (string)data["url"];
            string[] sArray = fbxURL.Split('.');
            if (sArray[sArray.Length - 1] != "json")
            {
                Debug.Log("result is not a json, ERROR.");
                return;
            }

            //============================下载模型============================
            string path = Application.dataPath + "/test/result.json";//设置保存路径
            WebRequest request2 = WebRequest.Create(fbxURL);//创建接受
            WebResponse response2 = request2.GetResponse();//接收响应
            Stream stream = response2.GetResponseStream();//创建接收流
            //检查目录是否存在,不存在则创建
            string dir = path.Substring(0, path.LastIndexOf("/"));
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);
            FileStream file = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write);//文件写入路径
            //返回内容总长度
            int max = (int)response2.ContentLength;
            int len = 0;
            while (len < max)
            {
                byte[] modelBytes = new byte[10240000];//byte容器
                int _len = stream.Read(modelBytes, 0, modelBytes.Length);//循环读取
                file.Write(modelBytes, 0, _len);//写入文件
                len += _len;
                //如果需要传递进度,可以这样算
                float progress = len / (float)max;
            }
            //写入完后关闭文件流和接收流
            file.Close();
            stream.Close();
        }
    }

    /// <summary>
    /// 文件转为byte[]
    /// </summary>
    private byte[] ObjectToBytes(string objectPath)
    {
        return File.ReadAllBytes(objectPath);
    }

    /// <summary>
    /// 文件转为Base64
    /// </summary>
    private string ObjectToBase64(string objectPath)
    {
        byte[] buffers = ObjectToBytes(objectPath);
        return Convert.ToBase64String(buffers);
    }

    /// <summary>
    /// Base64转为文件
    /// </summary>
    private void Base64ToSaveObject(string base64, string objectPath)
    {
        byte[] buffers = Convert.FromBase64String(base64);
        File.WriteAllBytes(objectPath, buffers);
    }
}

参考链接

  1. https://blog.csdn.net/qwe25878/article/details/85051911
  2. https://blog.csdn.net/yb0022/article/details/102754063
  3. https://blog.csdn.net/qq_34818497/article/details/106160110
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天富儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值