【技术博客】Unity引擎发送网络请求的方法 | week16
利用Unity引擎发送请求的方法
使用Unity发送请求,主要用到UnityWebRequest
这个类。灵境中使用了两种办法发送请求。
以JSON
格式发送请求
使用Newtonsoft.Json
中的JObject
类管理JSON
数据。具体使用方法请查阅官网https://www.newtonsoft.com/json。示例:var data = new JObject(); data["xxx"] = xxx;
使用本方法需要使用Unity
的协程函数StartCoroutine
,调用示例为StartCoroutine(SendRequest(data, url, callback, "POST"));
// 定义回调函数
delegate void SendRequestCallback(JObject returnData);
/// <summary>
/// 本方法将以Json格式向后端发送请求
/// </summary>
/// <param name="originJson">要发送的Json对象</param>
/// <param name="url"></param>
/// <param name="call">回调函数,不会处理异常,将信息原样返回</param>
/// <param name="type">可以是"POST"、"GET"等</param>
IEnumerator SendRequest(JObject originJson, string url, SendRequestCallback callback, string type)
{
// 将JObject转成json字符串
string sendData = JsonConvert.SerializeObject(originJson);
// 将字符串使用UTF-8编码成字节流
byte[] postBytes = System.Text.Encoding.GetEncoding("UTF-8").GetBytes(sendData);
// 创建UnityWebRequest对象,用以发送请求。使用type指定请求的类型。
using (UnityWebRequest webRequest = new UnityWebRequest(url, type))
{
// 设置要上传的数据
webRequest.uploadHandler = (UploadHandler)new UploadHandlerRaw(postBytes);
// 创建后端返回数据的接收端
webRequest.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
// 添加请求头。token是我们项目特有的
webRequest.SetRequestHeader("xxx", xxx);
// 必须要添加Content-Type请求头,明确指定以json形式传输
webRequest.SetRequestHeader("Content-Type", "application/json");
// 发送请求,并等待后端返回后继续调用。
yield return webRequest.SendWebRequest();
// 当后端炸了,可能返回一个空字符串,对空字符串进行json解析会导致错误
if (string.IsNullOrEmpty(webRequest.downloadHandler.text))
{
callback(null);
} else
{
// 将后端返回的json字符串转换成一个JObject对象,使用callback传递。
JObject returnData = JObject.Parse(webRequest.downloadHandler.text);
callback(returnData);
}
}
}
可以看出,发送请求的时候实际只是发送了一个字节流,因此这种方法的灵活度是最高的,不止可以发送json字符串,理论上可以以任何形式发送任何数据。
以表格Form
的形式发送数据
整体逻辑与上面的基本相同,但是unity对此封装的较为完善,步骤更简略,灵活度也更低。
使用WWWForm
类存储数据,使用方法可以参见:https://docs.unity3d.com/cn/2019.4/ScriptReference/WWWForm.html。示例:var form = new WWWForm(); form.AddField("xxx", xxx);
使用Form
形式可以发送二进制数据,可以用来上传图片,如form.AddBinaryData("file", texture.EncodeToJPG());
。有时候后端即需要二进制数据,同时有需要一些参数,那么以Form
的形式发送将变得十分方便。
IEnumerator UploadForm(WWWForm form, string url, SendRequestCallback callback)
{
// 可以直接指定以POST形式发送,也可以是其他形式。构造函数中直接传递WWWForm,不用进行字节流的转换等工作。
using (UnityWebRequest webRequest = UnityWebRequest.Post(url, form))
{
// 添加请求头。
webRequest.SetRequestHeader("xxx", xxx);
// 发送请求并等待返回
yield return webRequest.SendWebRequest();
// 与之前逻辑相同,不再赘述
if (string.IsNullOrEmpty(webRequest.downloadHandler.text))
{
callback(null);
}
else
{
JObject returnData = JObject.Parse(webRequest.downloadHandler.text);
callback(returnData);
}
}
}
从URL下载图片
delegate void DownloadImageCallback(Sprite image);
/// <summary>
/// 下载图片,转换成sprite的格式并传递给callback.
/// 如果网络出错,就传一个null
/// 目前验证过的图片格式:PNG, JPG
/// </summary>
/// <param name="url">图片的url</param>
/// <param name="callback"></param>
IEnumerator DownloadImage(string url, DownloadImageCallback callback)
{
using (UnityWebRequest webRequest = new UnityWebRequest(url))
{
// 将UnityWebRequest处理下载数据的类设置为DownloadHandlerTexture
// 之前用的是DownloadHandlerBuffer
DownloadHandlerTexture texDl = new DownloadHandlerTexture(true);
webRequest.downloadHandler = texDl;
// 发送请求
yield return webRequest.SendWebRequest();
// 为了提高方法的间接性,不让用户自己处理网络错误了。回调函数只会传递sprite
if (webRequest.result != UnityWebRequest.Result.ConnectionError
&& webRequest.result != UnityWebRequest.Result.ProtocolError)
{
// 没有网络错误,将下载的图片转换成sprite给回调函数
Sprite sprite = Sprite.Create(texDl.texture, new Rect(0, 0, texDl.texture.width, texDl.texture.height), new Vector2(0.5f, 0.5f));
callback(sprite);
} else
{
// 出现网络错误,传一个null
callback(null);
}
}
}
使用以上函数的方法
以上方法均需要使用Unity
的``StartCoroutine方法,因此不能写成静态类,必须要继承
MonoBehaviour`类然后挂到一个游戏物体上。
可以将以上方法封装为一个RequestSender
类,``StartCoroutine`写到这个类的里面,然后其他脚本想要发送请求,就可以借助匿名方法,用如下这种简便的方法发送请求:
// 以JSON发送POST请求
string url = "xxx";
JObject data = new JObject();
data["xxx"] = xxx;
FindObjectOfType<RequestSender>().SendPostRequest(data, url, (JObject returnData) => {
// 处理网络异常
if (returnData.Value<int>("code") != 0) {
Debug.Log("ERROR!");
return;
}
// 数据一般都会放在data段里
returnData = returnData.Value<JObject>("data");
Debug.Log(returnData.ToString());
...
});
// 从url下载图片
FindObjectOfType<RequestSender>().DownloadImage(url, (Sprite sprite) => {
// 处理异常
if (sprite = null) {
Debug.Log("ERROR!");
return;
}
// 比如下载图片后设置为头像
portrait.sprite = sprite;
...
});