C#网络编程入门之HTTP

一、概述

本文目的是通过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

posted @ 2020-05-27 14:36  seabluescn  阅读(2906)  评论(0编辑  收藏  举报