Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
我們這個Web服務器有了一個基本的門面以后,我們是時候來用它做點實際的事情了。還記得我們最早提到HTTP協議的用途是什么嗎?它叫超文本傳輸協議啊,所以我們必須考慮讓我們的服務器能夠接收到客戶端傳來的數據。因為我們目前完成了大部分的工作,所以對數據傳輸這個問題我們這里選擇以最簡單的GET和POST為例來實現,這樣我們今天的重點就落實在Get和Post的實現這個問題上來。而從原理上來講,無論Get方式請求還是Post方式請求,我們都可以在請求報文中獲得其請求參數,不同的是前者出現在請求行中,而后者出現在消息體中。例如我們傳遞的兩個參數num1和num2對應的數值分別是12和24,那么在具體的請求報文中我們都能找到類似“num1=12&num2=24”這樣的字符結構,所以只要針對這個字符結構進行解析,就可以獲得客戶端傳遞給服務器的參數啦。
首先我們來實現Get請求,Get是HTTP協議中默認的請求類型,我們平時訪問網頁、請求資源實際上都是通過Get方式實現的。Get方式請求需要通過類似“?id=001&option=10”這樣的形式附加在URL上,因此Get方式對瀏覽器來說是透明的,即用戶可以通過瀏覽器地址欄知道,這個過程中傳遞了哪些參數以及這些參數的值分別是什么。而由于瀏覽器的限制,我們通過這種方式請求的時候能夠傳遞的參數數目和長度都是有限的,而且當參數中存在中文數值的時候還需要對其進行編碼。Get方式請求相對簡單,我們下面來看看它的請求報文:
GET /?num1=23&num2=12 HTTP/1.1 Accept: text/html, application/xhtml+xml, image/jxr, */* Accept-Language: zh-Hans-CN,zh-Hans;q=0.5 User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586 Accept-Encoding: gzip, deflate Host: localhost:4040 Connection: Keep-Alive Cookie: _ga=GA1.1.1181222800.1463541781 1 2 3 4 5 6 7 8
此時我們可以注意到在請求報文第一行,即請求行中出現了“/?num1=23&num2=12”這樣的字樣,這就是客戶端傳遞給服務器的參數,我們很容易想到只需要將這個字段串中的“鍵”和“值”都解析出來,服務器就可以對這些數據進行處理然后返回給客戶端了。所以下面我們通過這樣的方式來實現,我們為HtttpRequest類增加了一個Parms屬性,它是一個鍵和值均為字符串類型的字典,我們使用這個字典來存儲和管理客戶端傳遞來的參數。
//獲取請求參數 if(this.Method=="GET" && this.URL.Contains('?')) this.Params=GetRequestParams(lines[0].Split(' ')[1].Split('?')[1]); 1 2 3
顯然我們首先需要判斷請求類型是否為GET以及請求中是否帶有參數,其方法是判斷請求地址中是否含有“?”字符。這里的lines是指將報文信息按行分割以后的數組,顯然請求地址在第一行,所以我們根據“?”分割該行數據以后就可以得到“num1=23&num2=12”這樣的結果,這里我們使用一個方法GetRequestParms來返回參數字典,這樣作做是為了復用方法,因為在處理Post請求的時候我們會繼續使用這個方法。該方法定義如下:
/// <summary> /// 從內容中解析請求參數并返回一個字典 /// </summary> /// <param name="content">使用&連接的參數字符串</param> /// <returns>如果存在參數則返回參數否則返回null</returns> protected Dictionary<string, string> GetRequestParams(string content) { //防御編程 if(string.IsNullOrEmpty(content)) return null; //按照&對字符進行分割 string[] reval=content.Split('&'); if(reval.Length <=0) return null; //將結果添加至字典 Dictionary<string, string> dict=new Dictionary<string, string>(); foreach(string val in reval) { string[] kv=val.Split('='); if(kv.Length <=1) dict.Add(kv[0], ""); dict.Add(kv[0],kv[1]); } //返回字典 return dict; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Post請求相對Get請求比較安全,因為它克服了Get請求參數長度的限制問題,而且由于它的參數是存放在消息體中的,所以在傳遞參數的時候對用戶而言是不可見的,我們平時接觸到的網站登錄都是這種類型,而復雜點的網站會通過驗證碼、Cookie等形式來避免爬蟲程序模擬登錄,在Web開發中Post請求可以由一個表單發起,可以由爬蟲程序如HttpWebRequest、WebClient等發起,下面我們重點來分析它的請求報文:
POST / HTTP/1.1 Accept: text/html, application/xhtml+xml, image/jxr, */* Accept-Language: zh-Hans-CN,zh-Hans;q=0.5 User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586 Accept-Encoding: gzip, deflate Host: localhost:4040 Connection: Keep-Alive Cookie: _ga=GA1.1.1181222800.1463541781 num1=23&num2=12 1 2 3 4 5 6 7 8 9 10
我們可以注意到此時請求行的請求方法變成了POST,而在報文結尾增加了一行內容,我們稱其為“消息體”,這是一個可選的內容,請注意它前面有一個空行。所以,當我們處理一個Posst請求的時候,通過最后一行就可以解析出客戶端傳遞過來的參數,和Get請求相同,我們這里繼續使用GetRequestParams來完成解析。
if(this.Method=="POST") this.Params=GetRequestParams(lines[lines.Length-1]); 1 2
現在我們來完成一個簡單地實例,服務器自然由我們這里設計的這個服務器來完成咯,而客戶端則由Unity來完成因為Unity有簡單的WWW可以使用。首先來編寫服務端,這個繼承HttpServer就好了,我們主要來寫這里的方法:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using HttpServerLib; using System.IO; namespace HttpServer { public class ExampleServer : HttpServerLib.HttpServer { /// <summary> /// 構造函數 /// </summary> /// <param name="ipAddress">IP地址</param> /// <param name="port">端口號</param> public ExampleServer(string ipAddress, int port) : base(ipAddress, port) { } public override void OnPost(HttpRequest request) { //獲取客戶端傳遞的參數 int num1=int.Parse(request.Params["num1"]); int num2=int.Parse(request.Params["num2"]); //設置返回信息 string content=string.Format("這是通過Post方式返回的數據:num1={0},num2={1}",num1,num2); //構造響應報文 HttpResponse response=new HttpResponse(content, Encoding.UTF8); response.StatusCode="200"; response.Content_Type="text/html; charset=UTF-8"; response.Server="ExampleServer"; //發送響應 ProcessResponse(request.Handler, response); } public override void OnGet(HttpRequest request) { //獲取客戶端傳遞的參數 int num1=int.Parse(request.Params["num1"]); int num2=int.Parse(request.Params["num2"]); //設置返回信息 string content=string.Format("這是通過Get方式返回的數據:num1={0},num2={1}",num1,num2); //構造響應報文 HttpResponse response=new HttpResponse(content, Encoding.UTF8); response.StatusCode="200"; response.Content_Type="text/html; charset=UTF-8"; response.Server="ExampleServer"; //發送響應 ProcessResponse(request.Handler, response); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
因為這里需要對Get和Post進行響應,所以我們這里對OnGet和OnPost兩個方法進行了重寫,這里的處理方式非常簡單,按照一定格式返回數據即可。下面我們來說說Unity作為客戶端這邊要做的工作。WWW是Unity3D中提供的一個簡單的HTTP協議的封裝類,它和.NET平臺下的WebClient、HttpWebRequest/HttpWebResponse類似,都可以處理常見的HTTP請求如Get和Post這兩種請求方式。
WWW的優勢主要是簡單易用和支持協程,尤其是Unity3D中的協程(Coroutine)這個特性,如果能夠得到良好的使用,常常能夠起到事倍功半的效果。因為WWW強調的是以HTTP短鏈接為主的易用性,所以相應地在超時、Cookie等HTTP頭部字段支持的完整性上無法和WebClient、HttpWebRequest/HttpWebRespons相提并論,當我們需要更復雜的HTTP協議支持的時候,選擇在WebClient、HttpWebRequest/HttpWebResponse上進行深度定制將會是一個不錯的選擇。我們這里需要的是發起一個簡單的HTTP請求,所以使用WWW完全可以滿足我們的要求,首先我們來看在Unity3D中如何發起一個Get請求,這里給出一個簡單的代碼示例:
//采用GET方式請求數據 IEnumerator Get() { WWW www=new WWW ("http://127.0.0.1:4040/?num1=12&num2=23"); yield return www; Debug.Log(www.text); } 1 2 3 4 5 6 7
現在我們是需要使用StartCoroutine調用這個方法就可以啦!同樣地,對于Post請求,我們這里采用一個WWWForm來封裝參數,而在網頁開發中我們通常都是借助表單來向服務器傳遞參數的,這里給出同樣簡單的代碼示例:
//采用POST方式請求數據 IEnumerator Post() { WWWForm form=new WWWForm (); form.AddField ("num1", 12); form.AddField ("num2", 23); WWW www=new WWW ("http://127.0.0.1:4040/", form); yield return www; Debug.Log (www.text); } 1 2 3 4 5 6 7 8 9 10
而運行這個實例,我們可以得到下面的結果:
都是誰告訴你做服務器開發一定要用Java的啊,現在我們可以寫出自己的服務器了,本篇結束
訪問中需要用到HTTPRequest組件,HTTPRequest發起HTTP請求,異步回調返回HTTPResponse。本篇就來給大家分享下在項目開發中HTTP訪問和下載的實現。
在unity中,www類雖然滿足了很多需求但也失去了一部分自由,下面我們用C#實現發送post請求,傳遞表單,并獲取或設置cookie。
private IEnumerator Login(string _url)
{
//設置鏈接
Uri url=new Uri(_url);
//設置http請求
HttpWebRequest request=(HttpWebRequest)HttpWebRequest.Create(url);
request.Method="POST";
//表單數據
byte[] _data=Encoding.UTF8.GetBytes("account=" + "CarefreeQ" + "&password=" + "CarefreeQ");
//內容類型
request.ContentType="application/x-www-form-urlencoded";
//內容長度
request.ContentLength=_data.Length;
//設置cookie,如要獲取則不能為空
request.CookieContainer=new CookieContainer();
//創建流
Stream stream=request.GetRequestStream();
//寫入數據
stream.Write(_data, 0, _data.Length);
stream.Close();
//開始接收響應
HttpWebResponse response=(HttpWebResponse)request.GetResponse();
//獲取cookie
string cookie=request.CookieContainer.GetCookieHeader(url);
//接收流
stream=response.GetResponseStream();
//內容長度
int max=(int)response.ContentLength;
int len=0;
//數據長度
_data=new byte[max];
while (len < max)
{
//寫入響應數據
int _len=stream.Read(_data, len, _data.Length);
len +=_len;
yield return new WaitForEndOfFrame();
}
//讀取數據
string text=Encoding.UTF8.GetString(_data);
}
在Unity的開發中,我們經常會把資源保存到網上,比如一些網格,assetbundle,配置文件,貼圖等等。我們希望在用戶使用時下載到本地。
privateIEnumeratorDownload(string_url)
{
//設置保存路徑
stringpath="自定義目錄";
//這個方法可以新建一個線程運行,來提高效率和降低卡頓,這里就不寫了
Uriurl=newUri(_url);
//創建接受
WebRequestrequest=WebRequest.Create(url);
//以下為接收響應的方法
WebResponseresponse=request.GetResponse();
//創建接收流
Streamstream=response.GetResponseStream();
//檢查目錄是否存在,不存在則創建
stringdir=path.Substring(0,path.LastIndexOf("/"));
if(!Directory.Exists(dir))
Directory.CreateDirectory(dir);
//文件寫入路徑
FileStreamfile=newFileStream(path,FileMode.OpenOrCreate,FileAccess.Write);
//返回內容總長度
intmax=(int)response.ContentLength;
intlen=0;
while(len<max)
{
//byte容器
byte[]data=newbyte[10240000];
//循環讀取
int_len=stream.Read(data,0,data.Length);
//寫入文件
file.Write(data,0,_len);
len+=_len;
//如果需要傳遞進度,可以這樣算
//floatprogress=len/(float)max;
yieldreturnnewWaitForEndOfFrame();
}
//寫入完后關閉文件流和接收流
file.Close();
stream.Close();
}
最后,以上就是給大家分享的關于HTTP訪問和下載實現,希望能對大家有所幫助。
GDC 2019大會上,Unity的Demo小組展示了一段名為“異教徒”的小短片。這是一段使用Unity引擎實時演算的技術demo,游戲的畫面逼真得讓人難以置信。值得一提的是,這個demo是在家用消費級的臺式機PC上運行的,游戲的畫面為1440P/30幀,好了,讓我們一起來看看吧!
這段“異教徒”技術demo演示是用最新版Unity引擎的“post-processing(后處理)”功能制作的,使用這一功能,Unity引擎為demo畫面加上了動態模糊、高光、景深、膠片顆粒、色彩分級等畫面特效。實現了無比逼真的畫面效果。
這段技術Demo中的光線效果全部都是實時演算的,它使用了移動檢測技術的光線解決方案。Demo最終呈現出來畫面讓人驚訝,而Unity也承諾不久之后就會放出完整版的短片。
視頻截圖:
*請認真填寫需求信息,我們會在24小時內與您取得聯系。