1、搭建HTTP服務器
- 使用別人做好的HTTP服務器軟件,一般作為資源服務器時使用該方式(學習階段建議使用)
- 自己編寫HTTP服務器應用程序,一般作為Web服務器或者短連接游戲服務器時使用該方式(工作后由后端程序員來做)
1.1 使用hfs搭建HTTP服務器,雙擊打開運行即可
1.2 添加服務器訪問文件夾
右鍵打開添加文件夾
選擇自己需要設置的訪問文件夾
?1.3 設置允許訪問和上傳權限
移到目標文件夾右鍵選擇Properties
創建允許訪問用戶憑證
?設置訪問權限
設置上傳權限
?設置刪除權限
2、C#的Http關鍵類介紹
2.1?HttpWebRequest類
重要方法
1)Create 創建新的WebRequest,用于進行HTTP相關操作
2)Abort? 如果正在進行文件傳輸,用此方法可以終止傳輸
3)GetRequestStream 獲取用于上傳的流
4)GetResponse 返回HTTP服務器響應
5)Begin/EndGetRequestStream 異步獲取用于上傳的流
6)Begin/EndGetResponse 異步獲取返回的HTTP服務器響應
重要成員
1)Credentials通信憑證,設置為NetworkCredential對象
2)PreAuthenticate是否隨請求發送一個身份驗證標頭,一般需要進行身份驗證時需要將其設置為true
3)Headers構成標頭的名稱/值對的集合
4)ContentLength發送信息的字節數上傳信息時需要先設置該內容長度
5)ContentType在進行POST請求時,需要對發送的內容進行內容類型的設置
6)Method操作命令設置
- ?WebRequestMethods.Http類中的操作命令屬性
- Get? ? ? ? ? ? ?獲取請求,一般用于獲取數據
- Post? ? ? ? ? ?提交請求,一般用于上傳數據,同時可以獲取
- Head? ? ? ? ? 獲取和Get一致的內容,只是只會返回消息頭,不會返回具體內容
- Put? ? ? ? ? ? ?向指定位置上傳最新內容
- Connect ? ? 表示與代理一起使用的HTTPCONNECT協議方法,該代理可以動態切換到隧道
- MkCol? ? ? ? 請求在請求 URI(統一資源標識符)指定的位置新建集合
2.2?HttpWebResponse類
重要方法
1)Close:釋放所有資源
2)GetResponseStream:返回從FTP服務器下載數據的流
重要成員
1)ContentLength:接受到數據的長度
2)ContentType:接受數據的類型
3)StatusCode:HTTP服務器下發的最新狀態碼
4)StatusDescription:HTTP服務器下發的狀態代碼的文本
5)BannerMessage:登錄前建立連接時HTTP服務器發送的消息
6)ExitMessage:HTTP會話結束時服務器發送的消息
7)LastModified:HTTP服務器上的文件的上次修改日期和時間
2.3?NetworkCredential
3、Http下載數據
3.1?檢測資源可用性
//利用Head請求參型,獲取信息//1.創建HTTP通訊用連接對象HttpWebRequest對象HttpWebRequest req = HttpWebRequest.Create(new Uri("https://t7.baidu.com/it/u=2604797219,1573897854&fm=193&f=GIF")) as HttpWebRequest;//2.設置請求類型或其它相關參數req.Method = WebRequestMethods.Http.Head;req.Timeout = 2000;//3.發送請求,獲取響應結果HttpWebResponse對象HttpWebResponse res = req.GetResponse() as HttpWebResponse;//4.判斷資源是否存在if (res.StatusCode == HttpStatusCode.OK){print("文件存在且可用");print(res.ContentLength);print(res.ContentType);res.Close();}else{print("文件不可用" + res.StatusCode);}
3.2?下載資源
//1.創建HTTP通訊用連接對象HttpWebRequest對象HttpWebRequest req2 = HttpWebRequest.Create(new Uri("https://t7.baidu.com/it/u=2604797219,1573897854&fm=193&f=GIF")) as HttpWebRequest;//2.設置請求類型或其它相關參數req2.Method = WebRequestMethods.Http.Get;req2.Timeout = 3000;//3.發送請求,獲取響應結果HttpWebResponse對象HttpWebResponse res2 = req2.GetResponse() as HttpWebResponse;//4.獲取響應數據流,寫入本地路徑if (res2.StatusCode == HttpStatusCode.OK){print(Application.persistentDataPath);using (FileStream fileStream = File.Create(Application.persistentDataPath + "/httpDownLoad.jpg")){Stream downLoadStream = res2.GetResponseStream();byte[] bytes = new byte[2048];//讀取數據int contentLength = downLoadStream.Read(bytes, 0, bytes.Length);//一點一點寫入本地while (contentLength > 0){fileStream.Write(bytes, 0, contentLength);contentLength = downLoadStream.Read(bytes, 0, bytes.Length);}fileStream.Close();downLoadStream.Close();res2.Close();}print("下載成功");}else{print("下載失敗" + res2.StatusCode);}
3.3?Get請求類型攜帶額外信息
1)協議部分
2)域名或公網IP部分
3)端口部分(默認80不需要寫)
4)虛擬目錄部分
5)參數部分
//我們在進行HTTP通信時,可以在地址后面加一些額外參數傳遞給服務端//一般在和短連接游戲服務器通訊時,需要攜帶額外信息// 舉例://http://www.aspxfans.com:8080/news/child/index.boardID=5&ID=24618&page=1//這個鏈接可以分成幾部分//1.協議部分:取決于服務器端使用的哪種協議//http: //一 普通的http超文本傳輸協議//https: //一 加密的超文本傳輸協議//2.域名部分://www.aspxfans.com//也可以填寫服務器的公網IP地址//3.端口部分://8080//可以不寫,如果不寫默認為80//4.虛擬目錄部分://news/child///域名后的/開始,到最后一個/之前的部分//5.文件名部分:// index.asp//?之前的最后一個 / 后的部分// 6.參數部分://boardID=5&ID=24618&page=1//?之后的部分就是參數部分,多個參數一&分隔開//這里有三個參數//boardID = 5//ID = 24618//page = 1//我們在和服務端進行通信時,只要按照這種規則格式進行通信,就可以傳遞參數給對象//主要可用于://1.web網站服務器//2.游戲短連接服務器//等
4、Http上傳文件
4.1?上傳文件到HTTP資源服務器需要遵守的規則
//上傳文件時內容的必備規則// 1:ContentType ="multipart/form-data;boundary=邊界字符串";// 2:上傳的數據必須按照格式寫入流中// --邊界字符串// Content - Disposition:form - data; name = "字段名字,之后寫入的文件2進制數據和該字段名對應"; filename = "傳到服務器上使用的文件名"// Content - Type:application / octet - stream(由于我們傳2進制文件所以這里使用2進制)// 空一行// (這里直接寫入傳入的內容)// --邊界字符串--// 3:保證服務器允許上傳// 4:寫入流前需要先設置ContentLength內容長度
4.2?上傳文件
//1.創建HttpWebRequest對象HttpWebRequest req = HttpWebRequest.Create("http://192.168.1.25:8000/HttpServer/") as HttpWebRequest;//2.相關設置(請求類型,內容類型,超時,身份驗證等)req.Method = WebRequestMethods.Http.Post;req.ContentType = "multipart/form-data;boundary=MrZhou";req.Timeout = 50000;req.Credentials = new NetworkCredential("ZT", "zt123");req.PreAuthenticate = true;//3.按格式拼接字符串并且轉為字節數組之后用于上傳//3-1.文件數據前的頭部信息// --邊界字符串// Content-Disposition:form-data;name="字段名字,之后寫入的文件2進制數據和該字段名對應";filename="傳到服務器上// Content-Type:application/octet-stream(由于我們傳2進制文件所以這里使用2進制)string head = "--MrZhou\r\n" +"Content-Disposition:form-data;name=\"file\";filename=\"http上傳的文件.jpg\"\r\n" +"Content-Type:application/octet-stream\r\n\r\n";//頭部拼接字符串規則信息的字節數組byte[] headBytes = Encoding.UTF8.GetBytes(head);//3-2.結束的邊界信息// --邊界字符串--byte[] endBytes = Encoding.UTF8.GetBytes("\r\n--MrZhou--\r\n");//4.寫入上傳流//4-1.設置上傳長度//4-2.先寫入前部分頭部信息//4-3.再寫入文件數據//4-4.在寫入結束的邊界信息using (FileStream localFileStream = File.OpenRead(Application.streamingAssetsPath + "/test.png")){//4-1.設置上傳長度//總長度 是前部分字符串 + 文件本身大小 + 后部分邊界字符串req.ContentLength = headBytes.Length + localFileStream.Length + endBytes.Length;//用于上傳的流Stream upLoadStream = req.GetRequestStream();//4-2.先寫入前部分頭部信息upLoadStream.Write(headBytes, 0, headBytes.Length);//4-3.再寫入文件數據byte[] bytes = new byte[2048];int contentLength = localFileStream.Read(bytes, 0, bytes.Length);while(contentLength > 0){upLoadStream.Write(bytes, 0, contentLength);contentLength = localFileStream.Read(bytes, 0, bytes.Length);}//4-4.在寫入結束的邊界信息upLoadStream.Write(endBytes, 0, endBytes.Length);upLoadStream.Close();localFileStream.Close();}//5.上傳數據,獲取響應HttpWebResponse res = req.GetResponse() as HttpWebResponse;if(res.StatusCode == HttpStatusCode.OK){print("上傳通訊成功");}else{print("上傳失敗" + res.StatusCode);}
5、Http管理類
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Events;public class HttpMgr
{private static HttpMgr instance = new HttpMgr();public static HttpMgr Instance => instance;//private string HTTP_PATH = "https://t7.baidu.com/it/";private string HTTP_PATH = "http://192.168.1.25:8000/HttpServer/";private string USER_NAME = "ZT";private string PASS_WORD = "zt123";/// <summary>/// 下載指定文件到本地指定路徑中/// </summary>/// <param name="url">遠程文件路徑</param>/// <param name="localPath">本地路徑</param>/// <param name="action">下載結束后的回調函數</param>public async void DownLoadFile(string url, string localFilePath, UnityAction<HttpStatusCode> action = null){HttpStatusCode result = HttpStatusCode.OK;await Task.Run(() =>{try{//判斷文件是否存在 Head//1.創建HTTP連接對象HttpWebRequest req = HttpWebRequest.Create(url) as HttpWebRequest;//2.設置請求類型 和 其他相關參數req.Method = WebRequestMethods.Http.Head;req.Timeout = 2000;//3.發送請求HttpWebResponse res = req.GetResponse() as HttpWebResponse;//存在才下載if(res.StatusCode == HttpStatusCode.OK){res.Close();//下載文件//1.創建HTTP連接對象req = HttpWebRequest.Create(url) as HttpWebRequest;//2.設置請求類型 和 其他相關參數req.Method = WebRequestMethods.Http.Get;req.Timeout = 2000;//3.發送請求res = req.GetResponse() as HttpWebResponse;//4.存儲數據到本地if(res.StatusCode == HttpStatusCode.OK){//存儲數據using (FileStream fileStream = File.Create(localFilePath)){Stream downLoadStream = res.GetResponseStream();byte[] bytes = new byte[2048];int contentLength = downLoadStream.Read(bytes, 0, bytes.Length);while (contentLength > 0){fileStream.Write(bytes, 0, contentLength);contentLength = downLoadStream.Read(bytes, 0, bytes.Length);}fileStream.Close();downLoadStream.Close();}result = HttpStatusCode.OK;}else{result = res.StatusCode;}}else{result = res.StatusCode;}res.Close();}catch (WebException e){result = HttpStatusCode.InternalServerError;Debug.LogError("文件下載失敗" + e.Message + e.Status);}});action?.Invoke(result);}/// <summary>/// 上傳文件/// </summary>/// <param name="fileName">傳到遠端服務器上的文件名</param>/// <param name="localFilePath">本地的文件路徑</param>/// <param name="action">上傳結束后的回調函數</param>public async void UpLoadFile(string fileName, string localFilePath, UnityAction<HttpStatusCode> action = null){HttpStatusCode result = HttpStatusCode.BadGateway;await Task.Run(() =>{try{HttpWebRequest req = HttpWebRequest.Create(HTTP_PATH) as HttpWebRequest;req.Method = WebRequestMethods.Http.Post;req.ContentType = "multipart/form-data;boundary=MrZhou";req.Timeout = 50000;req.Credentials = new NetworkCredential(USER_NAME, PASS_WORD);req.PreAuthenticate = true;//拼接字符串頭部string head = "--MrZhou\r\n" +"Content-Disposition:form-data;name=\"file\";filename=\"{0}\"\r\n" +"Content-Type:application/octet-stream\r\n\r\n";//替換文件名head = string.Format(head, fileName);Debug.Log(head);byte[] headBytes = Encoding.UTF8.GetBytes(head);//尾部的邊界字符串byte[] endBytes = Encoding.UTF8.GetBytes("\r\n--MrZhou--\r\n");using(FileStream localStream = File.OpenRead(localFilePath)){//設置長度req.ContentLength = headBytes.Length + localStream.Length + endBytes.Length;//寫入流Stream upLoadStream = req.GetRequestStream();//寫入頭部upLoadStream.Write(headBytes, 0, headBytes.Length);//寫入上傳文件byte[] bytes = new byte[2048];int contentLength = localStream.Read(bytes, 0, bytes.Length);while (contentLength > 0){upLoadStream.Write(bytes, 0, contentLength);contentLength = localStream.Read(bytes, 0, bytes.Length);}//寫入尾部upLoadStream.Write(endBytes, 0, endBytes.Length);upLoadStream.Close();localStream.Close();}HttpWebResponse res = req.GetResponse() as HttpWebResponse;//讓外部去處理結果result = res.StatusCode;res.Close();}catch (WebException e){Debug.LogError("上傳失敗" + e.Message + e.Status);}});action?.Invoke(result);}}