各位朋友大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是http://qinyuanpei.com。在我们这个 Web 服务器有了一个基本的门面以后,我们是时候来用它做点实际的事情了。还记得我们最早提到 HTTP 协议的用途是什么吗?它叫超文本传输协议啊,所以我们必须考虑让我们的服务器能够接收到客户端传来的数据。因为我们目前完成了大部分的工作,所以对数据传输这个问题我们这里选择以最简单的 GET 和 POST 为例来实现,这样我们今天的重点就落实在 Get 和 Post 的实现这个问题上来。而从原理上来讲,无论 Get 方式请求还是 Post 方式请求,我们都可以在请求报文中获得其请求参数,不同的是前者出现在请求行中,而后者出现在消息体中。例如我们传递的两个参数 num1 和 num2 对应的数值分别是 12 和 24,那么在具体的请求报文中我们都能找到类似“num1=12&num2=24”这样的字符结构,所以只要针对这个字符结构进行解析,就可以获得客户端传递给服务器的参数啦。
实现 Get 请求
首先我们来实现 Get 请求,Get 是 HTTP 协议中默认的请求类型,我们平时访问网页、请求资源实际上都是通过 Get 方式实现的。Get 方式请求需要通过类似“?id=001&option=10”这样的形式附加在 URL 上,因此 Get 方式对浏览器来说是透明的,即用户可以通过浏览器地址栏知道,这个过程中传递了哪些参数以及这些参数的值分别是什么。而由于浏览器的限制,我们通过这种方式请求的时候能够传递的参数数目和长度都是有限的,而且当参数中存在中文数值的时候还需要对其进行编码。Get 方式请求相对简单,我们下面来看看它的请求报文:
显然我们首先需要判断请求类型是否为 GET 以及请求中是否带有参数,其方法是判断请求地址中是否含有“?”字符。这里的 lines 是指将报文信息按行分割以后的数组,显然请求地址在第一行,所以我们根据“?”分割该行数据以后就可以得到“num1=23&num2=12”这样的结果,这里我们使用一个方法 GetRequestParms 来返回参数字典,这样作做是为了复用方法,因为在处理 Post 请求的时候我们会继续使用这个方法。该方法定义如下:
//按照&对字符进行分割 string[] reval = content.Split('&'); if (reval.Length <= 0) returnnull;
//将结果添加至字典 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; }
实现 Post 请求
Post 请求相对 Get 请求比较安全,因为它克服了 Get 请求参数长度的限制问题,而且由于它的参数是存放在消息体中的,所以在传递参数的时候对用户而言是不可见的,我们平时接触到的网站登录都是这种类型,而复杂点的网站会通过验证码、Cookie 等形式来避免爬虫程序模拟登录,在 Web 开发中 Post 请求可以由一个表单发起,可以由爬虫程序如 HttpWebRequest、WebClient 等发起,下面我们重点来分析它的请求报文:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using HttpServerLib; using System.IO;
namespaceHttpServer { public class ExampleServer : HttpServerLib.HttpServer { ///<summary> /// 构造函数 ///</summary> ///<param name="ipAddress">IP地址</param> ///<param name="port">端口号</param> publicExampleServer(string ipAddress, int port) : base(ipAddress, port) {
}
publicoverridevoidOnPost(HttpRequest request) { //获取客户端传递的参数 int num1 = int.Parse(request.Params["num1"]); int num2 = int.Parse(request.Params["num2"]);