mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
191 lines
6.0 KiB
C#
191 lines
6.0 KiB
C#
using Serein.Library.Api;
|
|
using Serein.Library.Utils;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Net;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Serein.Library.Http
|
|
{
|
|
|
|
/// <summary>
|
|
/// HTTP接口监听类
|
|
/// </summary>
|
|
public class WebServer
|
|
{
|
|
private readonly HttpListener listener; // HTTP 监听器
|
|
private Router router; // 路由器
|
|
private readonly RequestLimiter requestLimiter; //接口防刷
|
|
|
|
|
|
|
|
public WebServer()
|
|
|
|
{
|
|
listener = new HttpListener();
|
|
|
|
requestLimiter = new RequestLimiter(5, 8);
|
|
|
|
}
|
|
|
|
// 启动服务器
|
|
public WebServer Start(string prefixe, ISereinIOC serviceContainer)
|
|
{
|
|
try
|
|
{
|
|
router = new Router(serviceContainer);
|
|
if (listener.IsListening)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
if (!prefixe.Substring(prefixe.Length - 1, 1).Equals(@"/"))
|
|
{
|
|
prefixe += @"/";
|
|
}
|
|
|
|
|
|
listener.Prefixes.Add(prefixe); // 添加监听前缀
|
|
listener.Start(); // 开始监听
|
|
|
|
Console.WriteLine($"开始监听:{prefixe}");
|
|
Task.Run(async () =>
|
|
{
|
|
while (listener.IsListening)
|
|
{
|
|
var context = await listener.GetContextAsync(); // 获取请求上下文
|
|
_ = Task.Run(() => ProcessRequestAsync(context)); // 处理请求)
|
|
}
|
|
});
|
|
return this;
|
|
}
|
|
catch (HttpListenerException ex) when (ex.ErrorCode == 183)
|
|
{
|
|
return this;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 处理请求
|
|
/// </summary>
|
|
/// <param name="context"></param>
|
|
/// <returns></returns>
|
|
private async Task ProcessRequestAsync(HttpListenerContext context)
|
|
{
|
|
// 添加CORS头部
|
|
context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
|
|
context.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
|
context.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type");
|
|
|
|
// 处理OPTIONS预检请求
|
|
if (context.Request.HttpMethod == "OPTIONS")
|
|
{
|
|
context.Response.StatusCode = (int)HttpStatusCode.OK;
|
|
context.Response.Close();
|
|
return;
|
|
}
|
|
|
|
var isPass = await router.RouteAsync(context); // 路由解析
|
|
if (isPass)
|
|
{
|
|
context.Response.StatusCode = (int)HttpStatusCode.OK;
|
|
context.Response.Close(); // 关闭响应
|
|
}
|
|
else
|
|
{
|
|
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
|
context.Response.Close(); // 关闭响应
|
|
}
|
|
|
|
//var isPass = requestLimiter.AllowRequest(context.Request);
|
|
//if (isPass)
|
|
//{
|
|
// // 如果路由没有匹配,返回 404
|
|
// router.RouteAsync(context); // 路由解析
|
|
//}
|
|
//else
|
|
//{
|
|
// context.Response.StatusCode = (int)HttpStatusCode.NotFound; // 返回 404 错误
|
|
// context.Response.Close(); // 关闭响应
|
|
//}
|
|
|
|
// var request = context.Request;
|
|
// 获取远程终结点信息
|
|
//var remoteEndPoint = context.Request.RemoteEndPoint;
|
|
//// 获取用户的IP地址和端口
|
|
//IPAddress ipAddress = remoteEndPoint.Address;
|
|
//int port = remoteEndPoint.Port;
|
|
//Console.WriteLine("外部连接:" + ipAddress.ToString() + ":" + port);
|
|
}
|
|
|
|
// 停止服务器
|
|
public void Stop()
|
|
{
|
|
if (listener.IsListening)
|
|
{
|
|
listener?.Stop(); // 停止监听
|
|
listener?.Close(); // 关闭监听器
|
|
}
|
|
}
|
|
|
|
public void RegisterAutoController<T>()
|
|
{
|
|
//var instance = Activator.CreateInstance(typeof(T));
|
|
router.RegisterAutoController<T>();
|
|
}
|
|
|
|
/*public void RegisterRoute<T>(T controllerInstance)
|
|
{
|
|
router.RegisterRoute(controllerInstance);
|
|
}*/
|
|
}
|
|
/// <summary>
|
|
/// 判断访问接口的频次是否正常
|
|
/// </summary>
|
|
public class RequestLimiter(int seconds, int maxRequests)
|
|
{
|
|
private readonly ConcurrentDictionary<string, Queue<DateTime>> requestHistory = new ();
|
|
private readonly TimeSpan interval = TimeSpan.FromSeconds(seconds);
|
|
private readonly int maxRequests = maxRequests;
|
|
|
|
/// <summary>
|
|
/// 判断访问接口的频次是否正常
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public bool AllowRequest(HttpListenerRequest request)
|
|
{
|
|
var clientIp = request.RemoteEndPoint.Address.ToString();
|
|
var clientPort = request.RemoteEndPoint.Port;
|
|
var clientKey = clientIp + ":" + clientPort;
|
|
|
|
var now = DateTime.Now;
|
|
|
|
// 尝试从字典中获取请求队列,不存在则创建新的队列
|
|
var requests = requestHistory.GetOrAdd(clientKey, new Queue<DateTime>());
|
|
|
|
lock (requests)
|
|
{
|
|
// 移除超出时间间隔的请求记录
|
|
while (requests.Count > 0 && now - requests.Peek() > interval)
|
|
{
|
|
requests.Dequeue();
|
|
}
|
|
|
|
// 如果请求数超过限制,拒绝请求
|
|
if (requests.Count >= maxRequests)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 添加当前请求时间,并允许请求
|
|
requests.Enqueue(now);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
}
|