##区别
##封装的脚本
###同步方法
using System;
using UnityEngine;
using System.IO;
using System.Net;
using System.Text;
public class ClientSyncHttp {
private readonly int _timeout;
public ClientSyncHttp(string url, string body, Action callback = null, int timeout = 30) {
_timeout = timeout;
RequestHttpServer(new Uri(url), body, callback);
}
private void RequestHttpServer(Uri uri, string body, Action callback) {
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(uri);
request.ProtocolVersion = HttpVersion.Version11;
request.AutomaticDecompression = DecompressionMethods.None;
request.Method = "POST";
request.ContentType = "application/json;charset=UTF-8";
request.Timeout = _timeout*1000;
request.ReadWriteTimeout = 10*1000;
request.KeepAlive = false;
request.Proxy = null;
using (Stream requestStream = request.GetRequestStream()) {
byte[] bytes = Encoding.UTF8.GetBytes(body);
requestStream.Write(bytes, 0, bytes.Length);
requestStream.Close();
}
try {
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
if (responseStream == null) {
return;
}
StreamReader sr = new StreamReader(responseStream, Encoding.UTF8);
string result = sr.ReadToEnd().Trim();
sr.Close();
if (callback != null) {
callback(result);
}
}
catch (Exception e) {
Debug.Log(e);
}
}
}
###异步方法
using System;
using System.IO;
using UnityEngine;
using System.Net;
using System.Text;
namespace Joker.Network {
public class ClientAsyncHttp : MonoBehaviour {
public Action OnConnectFailed;
public Action OnRequestTimeOut;
private Action _onResponseSucceed;
private HttpWebRequest _webRequest;
[SerializeField]
private string _requestBody;
[SerializeField]
private string _responseString;
[SerializeField]
private string _dstUrl;
[SerializeField]
private float _requestTimer;
[SerializeField]
private float _timeOut;
[SerializeField]
private bool _isResponseTriggered;
[SerializeField]
private bool _isTimeOutTriggered;
[SerializeField]
private bool _isWaitingResponse;
private bool _isConnectFailedTriggered;
public static ClientAsyncHttp Create(string url, string body, Action callback, float? timeOut = null) {
float currentTimeOut = timeOut ?? 30f;
string name = string.Format("request_{0}", url);
ClientAsyncHttp instance = new GameObject(name, typeof(ClientAsyncHttp)).GetComponent();
instance._dstUrl = url;
instance._onResponseSucceed = callback;
instance._requestBody = body;
instance._timeOut = currentTimeOut;
return instance;
}
public void Request(string requestString = null) {
_isConnectFailedTriggered = false;
_isResponseTriggered = false;
_isTimeOutTriggered = false;
_isWaitingResponse = true;
_requestTimer = Time.realtimeSinceStartup;
if (!string.IsNullOrEmpty(requestString)) {
_requestBody = requestString;
}
StartAsyncRequest(new Uri(_dstUrl));
Debug.LogFormat("[request]:{0}, [post]:{1} at:{2}s, time out:{3}s", _requestBody, _dstUrl, _requestTimer, _timeOut);
}
private void Update() {
//when response received, trigger callback.
if (_isResponseTriggered) {
if (_onResponseSucceed != null) {
_onResponseSucceed(_responseString);
}
int elapsedMs = (int)((Time.realtimeSinceStartup - _requestTimer) * 1000);
Debug.LogFormat("[response]:{0}, elapsed:{1}ms ", _dstUrl, elapsedMs);
_isResponseTriggered = false;
_isWaitingResponse = false;
}
//check request time out.
if (CheckTimeOut() && _isWaitingResponse && !_isTimeOutTriggered) {
_isTimeOutTriggered = true;//标记超时状态触发
if (OnRequestTimeOut != null) {
OnRequestTimeOut();
}
_webRequest.Abort();//当Requst没有在限定的TimeOut内Response,就把此次请求视为夭折,立即结束此次请求。
Debug.LogFormat("[request]:{0} TIME OUT ", _dstUrl);
}
if (_isConnectFailedTriggered) {
_isConnectFailedTriggered = false;
if (OnConnectFailed != null) {
OnConnectFailed();
}
_webRequest.Abort();
Debug.LogFormat("[request]:{0} CONNECT FAILED ", _dstUrl);
}
}
private bool CheckTimeOut() {
//Debuger.LogFormat("CheckoutTimeOut, {0}, {1}, {2}", Time.realtimeSinceStartup, _requestTimer, _timeOut);
return Time.realtimeSinceStartup - _requestTimer > _timeOut;
}
private void StartAsyncRequest(Uri uri) {
_webRequest = (HttpWebRequest)WebRequest.Create(uri);
_webRequest.ProtocolVersion = HttpVersion.Version11;
_webRequest.AutomaticDecompression = DecompressionMethods.None;
_webRequest.Method = "POST";
_webRequest.ContentType = "application/json;charset=UTF-8";
//_webRequest.ReadWriteTimeout = (int)_timeOut * 1000;
_webRequest.KeepAlive = false;
_webRequest.Proxy = null;
_webRequest.BeginGetRequestStream(GetRequestStreamCallback, _webRequest);
}
private void GetRequestStreamCallback(IAsyncResult ar) {
HttpWebRequest request = (HttpWebRequest)ar.AsyncState;
//End the operation
Stream postStream;
try {
postStream = request.EndGetRequestStream(ar);
// Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(_requestBody);
// Write to the request stream.
//中文一个汉字占3个字节长度,所以write时以byte长度为准,不然输入中文时传输的长度不正确
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
// Start the asynchronous operation to get the response
request.BeginGetResponse(OnRequestServerResponse, request);
}
catch (Exception exception) {
if (exception.GetType() == typeof(WebException)) {
_isConnectFailedTriggered = true;
}
Debug.LogFormat("GetRequestStreamCallback Failed! {0}", exception);
}
}
private void OnRequestServerResponse(IAsyncResult ar) {
try {
HttpWebRequest request = (HttpWebRequest)ar.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(ar);
OnResponseReceived(response, request);
}
catch (Exception exception) {
throw exception;
}
}
private void OnResponseReceived(HttpWebResponse response, HttpWebRequest request) {
if (response.StatusCode == HttpStatusCode.OK) {
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse, Encoding.UTF8);
_responseString = streamRead.ReadToEnd();
streamResponse.Close();
streamRead.Close();
//Release the HttpWebResponse
response.Close();
_isResponseTriggered = true;
}
else {
Debug.LogFormat("接收请求失败,状态{0} ", response.StatusCode);
}
}
}
}
##测试案例
###首先用Python的Bottle库,模拟一个简单的web服务器
####服务端
from bottle import post, run, Bottle, static_file, request
@post('/test_http_timeout')
def test_http_timeout():
print "getpost %s" % request.body
import time
time.sleep(3)
return request.body
#app = MyApp()
run(host="192.168.1.138", port = 8090)
####客户端
using UnityEngine;
public class TestHttp : MonoBehaviour {
public GUISkin Skin;
// Use this for initialization
void Start() {
Skin.textField.fixedWidth = Screen.width;
Skin.textField.fixedHeight = 48;
Skin.textField.fontSize = 28;
Skin.button.fixedWidth = Screen.width;
Skin.button.fixedHeight = 48;
Skin.button.fontSize = 28;
Skin.label.fixedWidth = Screen.width;
Skin.label.fixedHeight = 48;
Skin.label.fontSize = 28;
}
private void SyncCallback(string result) {
_responseTextOfSync = result;
}
private void AsyncCallback(string result) {
_responseTextOfAsync = result;
}
private string _requestBodyOfSync = "";
private string _requestBodyOfAsync = "";
private string _responseTextOfSync;
private string _responseTextOfAsync;
void OnGUI() {
GUILayout.BeginArea(new Rect(0,0,Screen.width, Screen.height/2f));
GUILayout.Label("同步方法", Skin.label);
GUILayout.BeginHorizontal();
GUILayout.Label("Http请求:", Skin.label, GUILayout.Width(Screen.width/3f));
_requestBodyOfSync = GUILayout.TextField(_requestBodyOfSync, Skin.textField);
GUILayout.EndHorizontal();
if (GUILayout.Button("同步方法", Skin.button)) {
_responseTextOfSync = string.Empty;
new ClientSyncHttp("http://192.168.1.138:8090/update", _requestBodyOfSync, SyncCallback);
}
if (!string.IsNullOrEmpty(_responseTextOfSync)) {
GUILayout.Label(string.Format("服务端回执:{0}", _responseTextOfSync), Skin.label);
}
GUILayout.EndArea();
GUILayout.BeginArea(new Rect(0, Screen.width/2f, Screen.width, Screen.height/2f));
GUILayout.Label("异步方法", Skin.label);
GUILayout.Label("Http请求:", Skin.label, GUILayout.Width(Screen.width / 3f));
_requestBodyOfAsync = GUILayout.TextField(_requestBodyOfAsync, Skin.textField);
if (GUILayout.Button("异步请求", Skin.button)) {
_responseTextOfAsync = string.Empty;
new ClientAsyncHttp("http://192.168.1.138:8090/update", _requestBodyOfAsync, AsyncCallback);
}
if (!string.IsNullOrEmpty(_responseTextOfAsync)) {
GUILayout.Label(string.Format("服务端回执:{0}", _responseTextOfAsync), Skin.label);
}
GUILayout.EndArea();
}
}