【C#】一个简单的http服务器项目开发过程详解
这跟安装NoteJs程序运行脚本文件搭建一个简单Http服务器一样,相比起来,它的优点是可以开发的应用是免安装,跨平台的,放在移动盘上便捷的,这里着重讲http服务器实现的过程,以便自主实现特定的功能和服务。
打开Visual Studio开发工具,创建一个项目,
注意,项目开发语言是C#,使用的Net framework 4+ 框架,
创建的项目可以是以下三种
- Console 控制台
- WinForm 桌面程序
- WPF 桌面程序
新建项目
这里以最简单的Console控制台项目开发为例,
新建项目,选一个项目来创建:控制台应用(.NET Framework),如下图
编写代码
创建好一个项目后,在第一个代码Program.cs文件中,
获取本机IP
添加如下代码如下,先获取本机的IP列表
using System.Net; namespace ConsoleApp1 { class Program { static void Main(string[] args) { var IPs = Dns.GetHostEntry(Dns.GetHostName()).AddressList.Where(ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && ip.ToString().EndsWith(".1") != true).Select(ip => ip.ToString()).ToList(); //... } } }
继续写,获取第一个IP
var IP = IPs.FirstOrDefault();
启用HTTP服务
接下来,实现一个Http服务器
var server = new HttpListener(); var url = $"http://{IP}:8080/"; server.Prefixes.Add(url); server.Start(); Console.WriteLine("Http服务器已开启,用浏览器访问:" + url);
从上面代码中可看出,先传入IP和端口号,就可开启一个Http服务
被拒绝访问
可以试着编译运行看,能否正常运行,
此时运行可会出现一个错误提示:拒绝访问!
这就是触及到网络安全和权限问题了,有三种解决方案:
解决方案一
将IP换成’127.0.0.1’
缺点:只能本机访问
解决方案二
以管理员身份运行程序
缺点:每次运行前都要授权:确认以管理员身份
解决方案三
在访问控制规则中设置,
以管理员身份运行Shell终端(CMD),执行一条命令如下:
netsh http add urlacl url=http://{ip}:{port}/ user=Everyone
其中{ip}:{port} 换成自己的IP和端口号
这样,下次运行程序就不会再次弹出拒绝访问问题,
若想恢复,就执行一条命令,如下:
netsh http delete urlacl url=http://{ip}:{port}/
访问首页
那http服务器顺利开启后,
若要访问页面,那是看不到什么页面内容的,
处理请求
需要自己实现,添加一行代码如下
server.BeginGetContext((ar) => OnResult(server, ar), null);
从上面代码看,当请求访问它的时候,会调用那一个方法OnResult
实现那个方法OnResult,代码如下
private static void OnResult(HttpListener server, IAsyncResult ar) { if (!server.IsListening) return; var context = server.EndGetContext(ar); var request = context.Request; var response = context.Response; var method = request.HttpMethod.ToUpper(); //...待实现 if (server.IsListening) server.BeginGetContext((ar2)=>OnResult(server, ar2), null); }
从上面代码看,对写过后端服务代码的同学来说,就会觉得这很像服务器处理请求业务的逻辑
- request 是处理请求的对象
- response 是响应输出的对象
- method 是请求方法
在待实现那里,继续添加代码,
先判断请求地址,添加代码如下
var absUrl = HttpUtility.UrlDecode(request.Url.AbsolutePath);//request.RawUrl if (absUrl=="/" || absUrl=="/index.html"){ //... }
从上面代码看,判断到地址是请求加载首页的话,就去加载首页文件
加载文件
把写好的网页文件index.html放到运行程序文件对应的文件夹wwwroot下,
然后实现,读取本地文件内容,代码如下
var filePath = System.IO.Path.Combine(Environment.CurrentDirectory, "wwwroot", "index.html"); var contents = System.IO.File.ReadAllText(filePath); //...
响应内容
读取到内容,将输出给浏览器,代码如下
response.ContentType = "text/html;charset=UTF-8"; response.AddHeader("Content-Type", "text/html"); using (var writer = new System.IO.StreamWriter(response.OutputStream)) { writer.Write(contents); }
其中text/html,是表示文件内容类型,
注意,以上响应输出方法只能处理符合条件text/*内容类型的文件,
其它文件类型的文件,需要另外的方法来实现处理请求响应,
输出完成后,记得执行如下代码,关闭响应
response.Close();
内容类型
网页文件中还有加载的资源文件是比较常见的,它们的内容类型不一样,如下表:
名称 文件后缀名 内容类型 文本 .txt text/plain 网页 .html text/html 网页 .htm text/html 样式 .css text/css 数据 .json application/json 脚本 .js application/x-javascript 字体 .ttf application/x-font-ttf 图标 .ico image/x-icon 图片 .jpg image/jpeg 图片 .jpeg image/jpeg 更多文件内容类型,这里就不多列举了,如有需要请自行搜索
访问请求数据
当浏览器访问网页后,网页中有个资源标签需要加载服务器资源文件,还有网页脚本会请求访问服务器的数据,
所有加载资源的请求方法通常是GET,
判断请求方法
在之前的请求处理中,通过以下代码能判断
var method = request.HttpMethod.ToUpper(); if (method=="GET") { //... } else if (method=="POST") { //... }
处理GET请求
其中GET请求这里就不展开讲,这实现很简单吧,之前将加载网页文件就是处理GET请求来的,
有的请求地址中会带上查询数据,同如下这样
http://…com/q?csdn=zs1028
可判断请求地址中的查询部分,代码如下
var query = request.QueryString; //...
判断请求地址里的查询数据,再处理不同的请求响应
处理POST请求
是POST请求的话,通常会发来表单数据,
在请求处理中可以读取表单数据,代码如下:
// 检查是否为 multipart/form-data if (!request.ContentType.StartsWith("multipart/form-data", StringComparison.OrdinalIgnoreCase)) { throw new Exception("Only multipart/form-data is supported"); } var parser = new MultipartFormDataParser(request.InputStream); //...
其中HttpMultipartParser是使用Nuget包管理器安装的,当时是 2.1.7版本,
表单数据就在parser对象里,看里面有什么属性,
例如,前端页面操作上传的文件,在请求处理中可从parser对象的属性Files获取
处理请求响应
处理完请求后,需要响应数据,
如果是返回文本内容,就执行以下代码
response.AddHeader("Content-Type", "text/plain"); var contents = "ok"; using (var writer = new System.IO.StreamWriter(response.OutputStream)) { writer.Write(contents); }
如果返回JSON内容,就执行以下代码
var result = new { code = 0, errMsg = "ok" }; response.AddHeader("Content-Type", "application/json"); var contents = new JavaScriptSerializer().Serialize(result); using (var writer = new System.IO.StreamWriter(response.OutputStream)) { writer.Write(contents); }
从代码中看出,result就是object对象类型,可以转换成json序列化数据
写到这里,基本上就可以编译运行测试了,
一个简单HTTP服务器就这样实现处理,是不是感觉很容易,它的应用场景可以多了,请自由想象!
对前端开发来说,可以把前端项目生成的网页打包进一个程序中,轻松部署,再加上浏览器运行组件那就是跨平台的程序。
就写到这里,( _ )/~~拜拜