所谓的潇洒

导航

HttpListener

这是一个简易的web服务端,具有以下优点:

1.不用IIS即可部署,也可以做成安装包,实现傻瓜式部署

2.可以内嵌到winform中,方便与界面交互,方便与硬件对接

HttpServer通用代码部分如下

using DoneWin.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;

namespace MyProject
{
    public class HttpServer
    {
        HttpListener httpobj = new HttpListener();
        HttpHandle _httpHandle;
        public HttpServer(string ip, int port, HttpHandle httpHandle)
        {
            try
            {
                Init(ip, port, httpHandle);
            }
            catch(Exception ex)
            {
                //LogHelper.logger.Error(ex);
            }
        }

        public string HostUrl { get { return httpobj.Prefixes.First(); } }

        public void Init(string ip, int port, HttpHandle httpHandle)
        {
            try
            {
                _httpHandle = httpHandle;
                httpobj.Stop();
                httpobj.Prefixes.Clear();
                httpobj.Prefixes.Add($"http://{ip}:{port}/");
                httpobj.Start();
                httpobj.BeginGetContext(Result, null);
                LogHelper.logger.Info("HttpServer初始化完毕。");
            }
            catch (Exception ex)
            {
                //LogHelper.logger.Error(ex);
            }
        }

        private void Result(IAsyncResult ar)
        {
            try
            {                
                httpobj.BeginGetContext(Result, null);//继续异步监听
                //处理请求
                var context = httpobj.EndGetContext(ar);
                var request = context.Request;
                var response = context.Response;
                response.ContentType = "text/plain;charset=UTF-8";
                response.AddHeader("Content-type", "text/plain");
                response.ContentEncoding = Encoding.UTF8;
                
                try
                {
                    _httpHandle.Request = request;
                    _httpHandle.Response = response;
                    Type type = _httpHandle.GetType();
                    string methodName = request.RawUrl.Split('?').FirstOrDefault().Split('/').Last();
                    var method = type.GetMethod(methodName);
                    if (method == null)
                    {
                        response.StatusDescription = "Method Not Found!";
                        response.StatusCode = 404;
                    }
                    else
                    {
                        var result = (Byte[])method.Invoke(_httpHandle, null);
                        _httpHandle.WriteResponse(result);
                        response.StatusDescription = "ok";
                        response.StatusCode = 200;
                    }
                }
                catch(Exception ex)
                {
                    response.StatusDescription = ex.Message;
                    response.StatusCode = 500;
                }
            }
            catch(Exception ex)
            {
                //LogHelper.logger.Error(ex);
            }
        }

        public void Stop()
        {
            if (httpobj != null)
            {
                httpobj.Stop();
                httpobj.Abort();
            }
        }
    }

    public abstract class HttpHandle
    {
        public HttpListenerRequest Request;
        public HttpListenerResponse Response;

        public Dictionary<string, object> GetParams()
        {
            var paramDic = new Dictionary<string, object>();
            try
            {
                var byteList = new List<byte>();
                var byteArr = new byte[2048];
                int readLen = 0;
                int len = 0;
                //接收客户端传过来的数据并转成字符串类型
                do
                {
                    readLen = Request.InputStream.Read(byteArr, 0, byteArr.Length);
                    len += readLen;
                    byteList.AddRange(byteArr);
                } while (readLen != 0);
                string data = Encoding.UTF8.GetString(byteList.ToArray(), 0, len);
                //form-data转Dictionary
                string rqContentType = "--" + Request.ContentType.Split('=').Last();
                string[] paramNodes = data.Split(new string[] { rqContentType }, StringSplitOptions.RemoveEmptyEntries);
                for (int i = 0; i < paramNodes.Length; i++)
                {
                    if (!paramNodes[i].Trim('\r', '\n').StartsWith("Content-Disposition")) continue;
                    string[] dataLines = paramNodes[i].Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
                    string[] headers = dataLines[0].Split(';');
                    string key = headers[1].Split('=').Last().Trim('\"');
                    if (headers.Length == 2) paramDic.Add(key, dataLines[1]);//普通参数
                    else
                    {//文件参数
                        string fileName = headers[2].Split('=').Last().Trim('\"');
                        string contentType = dataLines[1].Split(':').Last().Trim();
                        //因为data经过了解码,从中读取文件内容(比如图片)可能文件损坏,所以从byteList读取文件的byte数组                 
                        byte[] searchBytes = Encoding.UTF8.GetBytes(dataLines[0] + "\r\n" + dataLines[1] + "\r\n\r\n");
                        int byteStartIndex = IndexOf(byteList.ToArray(), searchBytes, 0) + searchBytes.Length;
                        int byteEndIndex = IndexOf(byteList.ToArray(), Encoding.UTF8.GetBytes(rqContentType), byteStartIndex) - 1;

                        byte[] fileBytes = new byte[byteEndIndex - byteStartIndex];
                        byteList.CopyTo(byteStartIndex, fileBytes, 0, fileBytes.Length);
                        paramDic.Add(key, new FileParameter(fileBytes, fileName, contentType));
                    }
                }
            }
            catch (Exception ex)
            {
                //LogHelper.logger.Error(ex);
            }
            return paramDic;
        }

        public static int IndexOf(byte[] searchWithin, byte[] serachFor, int startIndex)
        {
            var index = 0;
            var startPos = Array.IndexOf(searchWithin, serachFor[0], startIndex);

            if (startPos != -1)
            {
                while (startPos + index < searchWithin.Length)
                {
                    if (searchWithin[startPos + index] == serachFor[index])
                    {
                        index++;
                        if (index == serachFor.Length)
                        {
                            return startPos;
                        }
                    }
                    else
                    {
                        startPos = Array.IndexOf(searchWithin, serachFor[0], startPos + index);
                        if (startPos == -1)
                        {
                            return -1;
                        }
                        index = 0;
                    }
                }
            }
            return -1;
        }

        public virtual void WriteResponse(byte[] result)
        {
            try
            {
                using (var stream = Response.OutputStream)
                {
                    stream.Write(result, 0, result.Length);
                }
            }
            catch (Exception ex)
            {
                //LogHelper.logger.Error(ex);
            }
        }
    }

    public class FileParameter
    {
        public byte[] File { get; set; }
        public string FileName { get; set; }
        public string ContentType { get; set; }
        public FileParameter(byte[] file) : this(file, null) { }
        public FileParameter(byte[] file, string filename) : this(file, filename, null) { }
        public FileParameter(byte[] file, string filename, string contenttype)
        {
            File = file;
            FileName = filename;
            ContentType = contenttype;
        }
    }
}
HttpServer.cs

接下来就是业务接口代码了

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

namespace MyProject
{
    public class myHttpHandle : HttpHandle
    {
        string apiPwd = string.Empty;
        public myHttpHandle (string pwd)
        {
            apiPwd = pwd;
        }

        public byte[] myApi1()
        {
            var jsonResult = new JsonResult { isSuccess = 0, msg = string.Empty };
            try
            {
                var paramDic = GetParams();
                if (!paramDic.ContainsKey("pwd") || !paramDic.ContainsKey("deviceType"))
                {
                    jsonResult.msg = "参数错误";
                    return jsonResult.ToBytes();
                }
                if (!string.IsNullOrEmpty(apiPwd) && apiPwd != paramDic["pwd"].ToString())
                {
                    jsonResult.msg = "密码错误";
                    return jsonResult.ToBytes();
                }

                //文件参数存本地
                foreach(string key in paramDic.Keys)
                {
                    if (paramDic[key] is FileParameter)
                    {
                        var fileParam = (FileParameter)paramDic.Last().Value;
                        File.WriteAllBytes($@"./{fileParam.FileName}", fileParam.File);
                    }
                }

                jsonResult.data = new  { name= "Jone"};
                jsonResult.isSuccess = 1;
            }
            catch (Exception ex)
            {
                //LogHelper.logger.Error(ex);
                jsonResult.msg = "服务器内部错误";
            }
            return jsonResult.ToBytes();
        }
    }

    public class JsonResult
    {
        public int isSuccess { get; set; }
        public string msg { get; set; }
        public object data { get; set; }

        public string ToJson()
        {
            StringBuilder sb = new StringBuilder("{\"isSuccess\":");
            sb.Append(isSuccess);
            sb.Append(",\"msg\":\"");
            sb.Append(msg);
            sb.Append("\",\"data\":{");
            if(data is Person)
            {
                var obj = (Person)data;
                sb.Append("\"name\":");
                sb.Append(obj.name);
            }
            sb.Append("}}");
            return sb.ToString();
        }

        public byte[] ToBytes()
        {
            string jsonResult = this.ToJson();
            if (string.IsNullOrEmpty(jsonResult)) return new byte[0];
            else return Encoding.UTF8.GetBytes(jsonResult);
        }
    }

    public class Person
    {
        public int name{ get; set; }
    }
}
HttpHandle.cs

接口写完,就可以写启动代码了,这里以嵌入到winform为例的,所以在主窗口加载时初始化,窗口关闭时释放

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace MyProject
{
    public partial class Form1 : Form
    {        
        //系统字段
        HttpServer httpSrv;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                httpSrv = new HttpServer("127.0.0.1", "8088", new myHttpHandle("Abc123"));
            }
            catch (Exception ex)
            {
                //LogHelper.logger.Error(ex);
            }
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            try
            {
                if (httpSrv != null) httpSrv.Stop();
            }
            catch { }           
        }
    }
}
Form1.cs

以上代码均是在.net 3.5基础上编写,win7及以上windows系统就免了安装.net framework

 

另外,在做相关项目时还解决了一个跨域问题,问题描述如下

  No 'Access-Control-Allow-Origin' header is present on the requested resource

解决办法是加上如下几行代码  

  response.AddHeader("Access-Control-Allow-Origin", "*");
  response.AddHeader("Access-Control-Allow-Method", "*");
  response.AddHeader("Access-Control-Allow-Headers", "Content-Type");
  response.AddHeader("Access-Control-Max-Age", "3600");
  response.AddHeader("Cache-Control", "no-cache");

posted on 2020-12-29 10:27  所谓的潇洒  阅读(479)  评论(0编辑  收藏  举报