一、概述
本文目的是通過C#代碼提供一個HTTP服務,正常情況下如果我們需要向外界提供HTTP服務,常規做法就是通過ASP.NET來實現,有時我們的應用程序或Windows服務需要向外提供一些簡單的HTTP服務就可以自己實現,從而避免部署IIS增加系統復雜性。這里必須強調是一些簡單的應用,如果應用比較復雜,涉及到路徑解析HTML解析等,還是用WEB方式實現比較靠譜。
將HTTP和UDP、TCP放在同一個系列實際上有一點不合適,因為UDP、TCP屬於傳輸層協議,HTTP屬於應用層協議,希望讀者首先有一個明確的了解。
二、 提供服務
首先啟動HHTP服務:
if (!HttpListener.IsSupported) { Console.WriteLine("服務器操作系統不支持建立Http Server,需要更高版本的操作系統!"); return; } HttpListener httpListener = new HttpListener(); try { Console.WriteLine("正在啟動Http服務"); int port = 9000; httpListener.Prefixes.Add($"http://*:{port}/"); httpListener.Start(); Console.WriteLine("Http服務啟動成功。"); } catch (Exception ex) { Console.WriteLine($"啟動Http服務出現異常:{ex.Message}"); return; }
進行監聽:
while (true) { Console.WriteLine("開始監聽..."); HttpListenerContext context = httpListener.GetContext(); HttpListenerRequest request = context.Request; string Method = request.HttpMethod.ToUpper(); Console.WriteLine($"收到請求,URL:{ request.Url} Method:{Method}"); Response(context, "hello"); }
代碼循環進行監聽,GetContext方法會引起阻塞,當收到瀏覽器請求時,服務器立即返回“Hello”。
Response方法實現如下:
private static void Response(HttpListenerContext context, string responseTxt) { HttpListenerResponse response = context.Response; response.ContentType = "html"; response.ContentEncoding = Encoding.UTF8; using (Stream output = response.OutputStream) { byte[] buffer2 = Encoding.UTF8.GetBytes(responseTxt); output.Write(buffer2, 0, buffer2.Length); } }
此時打開瀏覽器輸入地址 http://localhosthost:9000/ 看一下能否看到結果。(如果需要通過其他機器訪問,本機要開放防火牆對應端口。)
注意:程序需要以管理員模型運行才能提供服務。
具體辦法:工程新增應用程序清單文件:app.manifest,修改配置信息如下:
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> <security> <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> </requestedPrivileges> </security> </trustInfo> |
三、 響應
通過request.HttpMethod可以取得協議類型,對於GET和POST方法將采取不同的處理方式。
通過request.RawUrl可以取得URL路徑,並進行解析,通過request.QueryString可以用戶輸入的參數值。
if (Method == "GET") { Console.WriteLine($"Get:RawURL:{ request.RawUrl}"); if (request.RawUrl.StartsWith("/version")) { Response(context, "Simple Http Server Ver:0.11"); continue; } else { string username = request.QueryString["username"]; string pwd = request.QueryString["pwd"]; Response(context, $"Welcome:{username}"); continue; } }
以上代碼,如果輸入:http://localhost:9000?username=hahaha
輸出:Welcome:hahaha
在POST方法下,仍然可以通過request.QueryString取得用戶通過URL輸入的參數,但通過Body傳輸的數據需要通過其他方式進行讀取。
if (Method == "POST") { Console.WriteLine($"POST:RawURL:{ request.RawUrl}"); string content = GetPostInput(request); Console.WriteLine($"Content:{ content}"); Response(context, "\"{'Result':'Success','Message':'Hello'}\""); continue; }
GetPostInput方法實現如下:
private static string GetPostInput(HttpListenerRequest request) { Stream s = request.InputStream; int count = 0; byte[] buffer = new byte[1024]; StringBuilder builder = new StringBuilder(); while ((count = s.Read(buffer, 0, 1024)) > 0) { builder.Append(Encoding.UTF8.GetString(buffer, 0, count)); } s.Flush(); s.Close(); s.Dispose(); return builder.ToString(); }
為了方便起見,輸入輸出的數據最好采用json格式。
四、調試
可以通過Chrome或Postman來進行調試。
傳送門:
C#網絡編程入門系列包括三篇文章:
(一)C#網絡編程入門之UDP
(二)C#網絡編程入門之TCP
(三)C#網絡編程入門之HTTP