http服务类HttpServer,目前只处理contentType ="application/x-www-form-urlencoded"的请求
class HttpServer
{
//创建委托。用于调用相应请求处理
public delegate void respNoticeDelegate(Dictionary<string, string> data, HttpListenerResponse resp, string route
, string request_type = "get");
public event respNoticeDelegate respNotice;
private HttpListener listener ;
public HttpServer()
{
listener = new HttpListener();
}
public void close()
{
listener.Stop();//停止监听
}
//开始监听
public void Start(int port)
{
if (!HttpListener.IsSupported)
{
Console.WriteLine("无法在当前系统上运行服务" + DateTime.Now.ToString());
return;
}
if (port == 0)
{
System.Console.WriteLine("没有监听端口");
}
var url = string.Format("http://127.0.0.1:{0}{1}", port, "/");
System.Console.WriteLine(url);
listener.Prefixes.Add(url); //监听
listener.Start();
listener.BeginGetContext(GetContextCallBack, listener);
}
private void GetContextCallBack(IAsyncResult asy)
{
listener = asy.AsyncState as HttpListener;
if (!listener.IsListening) return;//如果已经停止监听了就直接返回
listener.BeginGetContext(new AsyncCallback(GetContextCallBack), listener);
var context = listener.EndGetContext(asy);
var req = context.Request;
var rsp = context.Response;
//对接口url处理
string route = HandlerReq(req.RawUrl);//获取当前路由
//解析接口参数
Dictionary<string, string> data = new Dictionary<string, string>();
data = HandleHttpMethod(context, rsp, route);
//将解析后的结果 通知
doNoticeEvent(data, rsp, route, context.Request.HttpMethod);
}
/// <summary>
/// 输出结果(返回结果)
/// </summary>
/// <param name="content">结果</param>
/// <param name="rsp">httprespon对象</param>
/// <returns></returns>
public string responData(string content, HttpListenerResponse rsp)
{
try
{
using (var stream = rsp.OutputStream)
{
rsp.StatusCode = 200;
rsp.ContentType = "text/html;charset=UTF-8";//告诉客户端返回的ContentType类型为纯文本格式,编码为UTF-8
rsp.AddHeader("Content-type", "application/json");//添加响应头信息
rsp.ContentEncoding = Encoding.UTF8;
//后台跨域请求;允许跨域,必须配置
rsp.AppendHeader("Access-Control-Allow-Origin", "*");//允许跨域
rsp.AppendHeader("Access-Control-Allow-Credentials", "true");
rsp.AppendHeader("Access-Control-Allow-Headers", "Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,X-Requested-With");
rsp.AppendHeader("Access-Control-Max-Age", "86400");
byte[] dataByte = Encoding.UTF8.GetBytes(content);
stream.Write(dataByte, 0, dataByte.Length);
stream.Close();
}
}
catch (Exception e)
{
rsp.Close();
return e.Message;
}
rsp.Close();
return "";
}
/// <summary>
/// 对客户端来的url处理
/// </summary>
/// <param name="url"></param>
private string HandlerReq(string url)
{
try
{
string[] arr_str = url.Split('?');
if (arr_str.Length > 0)
{
return arr_str[0];//如下:/api/test
}
return "";
}
catch (Exception e)
{
return "";
}
}
//处理接口所传数据 Post和Get 获取数据
private Dictionary<string, string> HandleHttpMethod(HttpListenerContext context, HttpListenerResponse resp, string route)
{
Dictionary<string, string> return_data = new Dictionary<string, string>();
try {
string contentType = context.Request.ContentType == null ? "" : context.Request.ContentType;
if (contentType == "application/x-www-form-urlencoded")
{
switch (context.Request.HttpMethod)
{
case "GET":
var data = context.Request.QueryString;
string url = context.Request.Url.ToString();
string[] pars = url.Split('?');
if (pars.Length == 0)
{
return return_data;
}
if (pars.Length <= 1) return return_data;
string canshus = pars[1];
if (canshus.Length > 0)
{
string[] canshu = canshus.Split('&');
foreach (string i in canshu)
{
string[] messages = i.Split('=');
datazParamAdd(messages[0], messages[1], return_data);
}
}
break;
case "POST":
using (Stream stream = context.Request.InputStream)
{
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
string strParam = reader.ReadToEnd();
System.Console.WriteLine(strParam);
string[] keyValue = strParam.Split('&');
foreach (string param in keyValue)
{
string[] kv = param.Split('=');
datazParamAdd(kv[0], kv[1], return_data);
}
}
break;
}
}
}catch(Exception ex)
{
System.Console.WriteLine("err:" + ex.Message);
}
return return_data;
}
/// <summary>
/// 将解析后的参数通知事件
/// </summary>
/// <param name="data">解析后的参数字典</param>
/// <param name="rsp">respon对象</param>
/// <param name="route">路由</param>
/// <param name="method">请求方法</param>
public void doNoticeEvent(Dictionary<string, string> data, HttpListenerResponse rsp, string route, string method = "")
{
//调用请求处理代理方法
respNotice?.Invoke(data, rsp, route, method);
}
public void datazParamAdd(string k, string v, Dictionary<string, string> dataParam)
{
if (dataParam.ContainsKey(k))
{
dataParam[k] = v;
}
else
{
dataParam.Add(k, v);
}
}
}
在winform界面中启动服务和调用处理,请求处理基类为BaseController,派生类DllController
class BaseController
{
}
class DllController : BaseController
{
public string getKey(string method, string seed)
{
//在这里处理http请求的业务逻辑
return "处理结果";
}
}
winform页面代码,采用多线程调用处理类,利用反射,根据请求路径,给对应的方法参数传值并执行
public partial class FrmWebserver : Form
{
HttpServer httpServer;
//加载程序集,用于反射
Assembly assembly = Assembly.Load("fcar_webserver");
Type dllControllerType = null;
//http服务路由对应的处理接口类
Dictionary<string, BaseController> httpRoutes = new Dictionary<string, BaseController>();
public FrmWebserver()
{
InitializeComponent();
}
private void FrmWebserver_Load(object sender, EventArgs e)
{
//在这里配置请求路径对应的接口处理类,单例模式
DllController dllController = new DllController();
httpRoutes.Add("/keyDll/getKey", dllController);
httpServer = new HttpServer();
httpServer.respNotice += dataHandle;//回调方法,接收到http请求时触发
ThreadPool.SetMinThreads(3, 3);//配置线程池
ThreadPool.SetMaxThreads(100, 100);
}
private void btnStart_Click(object sender, EventArgs e)
{
try {
if (btnStart.Text == "启动")
{
httpServer.Start(int.Parse(txtPort.Text));
btnStart.Text = "关闭";
}
else
{
httpServer.close();
this.Close();
}
}catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
/// <summary>
/// 收到请求的回调函数
/// </summary>
/// <param name="data">客户端请求的数据</param>
/// <param name="resp">respon对象</param>
/// <param name="route">请求路径,如/keyDll/getKey</param>
/// <param name="request_type">请求类型,get或者post</param>
public void dataHandle(Dictionary<string, string> data, HttpListenerResponse resp, string route = "", string request_type = "get")
{
//采用线程池,提高并发处理
ThreadPool.QueueUserWorkItem(p =>
{
Result result = new Result();
result.success = false;
try
{
BaseController controller = httpRoutes.ContainsKey(route) ? httpRoutes[route] : null;
if (route.StartsWith("/keyDll"))
{
//根据方法名通过反射,执行对应的方法
string methodName = route.Substring(route.LastIndexOf("/") + 1);
DllController dllController = (DllController)controller;
if (dllControllerType == null)
dllControllerType = assembly.GetType("fcar_webserver.DllController");
MethodInfo methodInfo = dllControllerType.GetMethod(methodName);
List<object> objectList = new List<object>();
foreach (ParameterInfo parameterInfoItem in methodInfo.GetParameters())
{
if (data.ContainsKey(parameterInfoItem.Name))
{
if (parameterInfoItem.ParameterType == typeof(String))
{
objectList.Add(data[parameterInfoItem.Name]);
}
else if (parameterInfoItem.ParameterType == typeof(int))
{
objectList.Add(int.Parse(data[parameterInfoItem.Name]));
}
}
}
if (objectList.Count == methodInfo.GetParameters().Length)
{
string strBack = methodInfo.Invoke(dllController, objectList.ToArray()).ToString();
result.success = true;
result.data = strBack;
}
else
{
result.msg = "参数不对!";
}
}
else
{
result.code = 404;
httpServer.responData("404", resp);
}
}
catch (Exception ex)
{
System.Console.WriteLine(ex.Message);
result.msg = "请求失败";
}
httpServer.responData(JsonConvert.SerializeObject(result), resp);
});
}
}
返回结果类
public class Result
{
public bool success { get; set; }//结果
public String msg { get; set; }//结果信息
public Object data { get; set; }
public Object result { get; set; }//
public int code { get; set; }//
public String token { get; set; }//请求接口的凭证
public Result(bool result, String msg, Object data)
{
this.success = result;
this.msg = msg;
this.data = data;
}
public Result(bool result, String msg)
{
this.success = result;
this.msg = msg;
}
public Result()
{
}
}