|
先声明一下,由于这篇是基础篇主要是通过这篇文章让大家对使用HttpListener响应Http请求有个大概了解,所以正式的花样轮子在下一篇推出,敬请期待 ^_^
嗯哼,还有,我标题党了一下,看完我这个系列的话,在特定场景下可抛弃IIS,但如果完全抛弃IIS就不要想咯 ^_^
HttpListener:提供一个简单的、可通过编程方式控制的 HTTP 协议侦听器。(好吧,我承认这句是从MSDN上抄过来的)
既然引子出来了,说明我们要开始玩Http请求了。
那么我们基础篇要做的是,如何把一个 html 文件从服务器返回给客户端。
1.监听一个地址前缀,如:http://localhost/
2.解析Url
3.执行Url所代表的指令
4.返回执行结果
下面贴出的是主要的代码,实际源码中做了一些其他的处理,比如多线程防止界面卡死、HttpListener运行环境检测、资源释放、容错等等。
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时需要做几个事情:
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
1.判断Url的请求文件后缀是否支持
2.检索本地文件
3.如果文件存在则返回文件,不存在则返回异常(此处在后续扩展活增加更多可变性,比如一些动态执行方法等)
PS:由于此处代码涉及几个方法就不贴了,直接看源码吧。(ProcessHttpRequest 方法)
请求一个简单的Hello World的html文件,此处有个细节,就是浏览器会发送ico请求。聪明的你如果想要显示ico应该知道怎么办吧 ^_^
请求一个不支持的后缀,如:htm
1.丰富一下请求文件类型
2.支持执行方法的请求
3.在HttpListner里玩一玩LUA脚本
最后,我要放源码了 ^_^
http://git.oschina.net/doddgu/WebServerDemo
|
|
|