Unity使用UnityWebRequest实现HTTP网络连接
UnityWebRequest
Unity中UnityWebRequest
和WWW
都可以实现HTTP请求,但UnityWebRequest
是Unity新的网络请求方式,新版本已经对WWW
API弃用了。
UnityWebRequests
处理与Web服务器的HTTP通信流。 需要注意的其他对象,特别是DownloadHandler
和UploadHandler
,分别管理下载和上传数据。
注意:一旦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);
}
}