HttpListener:提供一个简单的、可通过编程方式控制的 HTTP 协议侦听器。(好吧,我承认这句是从MSDN上抄过来的)
既然引子出来了,说明我们要开始玩Http请求了。
那么我们基础篇要做的是,如何把一个 html 文件从服务器返回给客户端。
一个Http请求我们需要做些什么?
1.监听一个地址前缀,如:http://localhost/
2.解析Url
3.执行Url所代表的指令
4.返回执行结果
监听一个Http请求
下面贴出的是主要的代码,实际源码中做了一些其他的处理,比如多线程防止界面卡死、HttpListener运行环境检测、资源释放、容错等等。
class="code_img_closed" src="/Upload/Images/2015010412/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('eb7781ca-7516-458b-b472-4f5e70b09108',event)" src="/Upload/Images/2015010412/2B1B950FA3DF188F.gif" alt="" />1 HttpListener server = new HttpListener(); 2 try 3 { 4 MakeHttpPrefix(server); 5 server.Start(); 6 } 7 catch (Exception ex) 8 { 9 Logger.Exit("无法启动服务器监听,请检查网络环境。"); 10 } 11 12 IAsyncResult result = null; 13 while (!_terminated) 14 { 15 while (result == null || result.IsCompleted) 16 { 17 result = server.BeginGetContext(new AsyncCallback(ProcessHttpRequest), server); 18 } 19 _ready = true; 20 Thread.Sleep(10); 21 } 22 23 server.Stop(); 24 server.Abort(); 25 server.Close();View Code
解析Url
解析Url时需要做几个事情:
1.Url的长度限制
2.是否包含特殊字符
3.拆分指令与参数
1 /// <summary> 2 /// Url辅助类:对Url进行初步的解析 3 /// </summary> 4 public class UrlHelper 5 { 6 const int MAX_URI_LENGTH = 512; 7 string _scriptName = string.Empty; 8 CommandResult _parseResult = CommandResult.Success; 9 NameValueCollection _parameters = new NameValueCollection(); 10 char[] _uriInvalidChar = new char[] { '/', '\\' }; 11 char[] _pathInvalidChar = new char[] { '/', '\\', ':', '*', '?', '\"', '<', '>', '|' }; 12 public Uri _uri = null; 13 14 public string ScriptName 15 { 16 get { return _scriptName; } 17 } 18 19 public NameValueCollection Parameters 20 { 21 get { return _parameters; } 22 } 23 24 public CommandResult ParseResult 25 { 26 get { return _parseResult; } 27 } 28 29 public UrlHelper(Uri originalUri) 30 { 31 _uri = originalUri; 32 33 if (IsUriLengthError()) 34 { 35 return; 36 } 37 38 if (CheckPathAndQuery()) 39 { 40 ParsePathAndQuery(); 41 } 42 } 43 44 private bool IsUriLengthError() 45 { 46 if (_uri == null || _uri.ToString().Length > MAX_URI_LENGTH) 47 { 48 _parseResult = CommandResult.UrlTooLong; 49 return true; 50 } 51 return false; 52 } 53 54 private bool CheckPathAndQuery() 55 { 56 string pathAndQuery = _uri.PathAndQuery.Substring(1); 57 58 if (IsUrlInvalidChar(pathAndQuery)) 59 { 60 return false; 61 } 62 63 if (pathAndQuery.IndexOfAny(_uriInvalidChar) >= 0) 64 { 65 _parseResult = CommandResult.UrlInvalidChar; 66 return false; 67 } 68 else if (pathAndQuery.Length == 0) 69 { 70 _parseResult = CommandResult.NoExistsMethod; 71 return false; 72 } 73 74 string[] splitPathAndQuery = new string[] { }; 75 if (IsFileNameInvalidChar(pathAndQuery, splitPathAndQuery)) 76 { 77 return false; 78 } 79 80 return true; 81 82 } 83 84 private bool IsFileNameInvalidChar(string pathAndQuery, string[] splitPathAndQuery) 85 { 86 splitPathAndQuery = pathAndQuery.Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries); 87 if (splitPathAndQuery[0].IndexOfAny(_pathInvalidChar) >= 0) 88 { 89 _parseResult = CommandResult.FileNameInvalidChar; 90 return true; 91 } 92 return false; 93 } 94 95 private bool IsUrlInvalidChar(string pathAndQuery) 96 { 97 if (pathAndQuery.IndexOfAny(_uriInvalidChar) >= 0) 98 { 99 _parseResult = CommandResult.UrlInvalidChar; 100 return true; 101 } 102 return false; 103 } 104 105 private void ParsePathAndQuery() 106 { 107 string[] splitPathAndQuery = _uri.PathAndQuery.Substring(1).Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries); 108 SetScriptNameAndParameters(splitPathAndQuery); 109 } 110 111 private void SetScriptNameAndParameters(string[] splitPathAndQuery) 112 { 113 _scriptName = splitPathAndQuery[0]; 114 115 if (splitPathAndQuery.Length > 1) 116 { 117 _parameters = HttpUtility.ParseQueryString(splitPathAndQuery[1], Encoding.UTF8); 118 } 119 } 120 }View Code
执行Url所代表的指令和返回执行结果
1.判断Url的请求文件后缀是否支持
2.检索本地文件
3.如果文件存在则返回文件,不存在则返回异常(此处在后续扩展活增加更多可变性,比如一些动态执行方法等)
PS:由于此处代码涉及几个方法就不贴了,直接看源码吧。(ProcessHttpRequest 方法)
有图有真相
请求一个简单的Hello World的html文件,此处有个细节,就是浏览器会发送ico请求。聪明的你如果想要显示ico应该知道怎么办吧 ^_^
请求一个不支持的后缀,如:htm
下一次我们玩什么?
1.丰富一下请求文件类型
2.支持执行方法的请求
3.在HttpListner里玩一玩LUA脚本
最后,我要放源码了 ^_^
http://git.oschina.net/doddgu/HttpListenerDemo