[fix]修正UdpServer在接收广播时连续启动接收的错误,在StarAgent中,此时可能收到广播包,SocketFlags是Broadcast,需要清空,否则报错“参考的对象类型不支持尝试的操作”; 无需设置SocketOptionName.PacketInformation,在ReceiveMessageFromAsync时会自动设置,并且支持ipv6;
石头 authored at 2024-10-10 00:36:00 石头 committed at 2024-10-10 00:45:43
5.20 KiB
X
using System.ComponentModel;
using NewLife.Net;

namespace NewLife.Http;

/// <summary>Http服务器</summary>
[DisplayName("Http服务器")]
public class HttpServer : NetServer, IHttpHost
{
    #region 属性
    /// <summary>Http响应头Server名称</summary>
    public String ServerName { get; set; }

    /// <summary>路由映射</summary>
    public IDictionary<String, IHttpHandler> Routes { get; set; } = new Dictionary<String, IHttpHandler>(StringComparer.OrdinalIgnoreCase);
    #endregion

    /// <summary>实例化</summary>
    public HttpServer()
    {
        Name = "Http";
        Port = 80;
        ProtocolType = NetType.Http;

        var ver = GetType().Assembly.GetName().Version ?? new Version();
        ServerName = $"NewLife-HttpServer/{ver.Major}.{ver.Minor}";
    }

    ///// <summary>创建会话</summary>
    ///// <param name="session"></param>
    ///// <returns></returns>
    //protected override INetSession CreateSession(ISocketSession session) => new HttpSession();

    /// <summary>为会话创建网络数据处理器。可作为业务处理实现,也可以作为前置协议解析</summary>
    /// <param name="session"></param> 
    /// <returns></returns>
    public override INetHandler? CreateHandler(INetSession session) => new HttpSession();

    #region 方法
    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map(String path, IHttpHandler handler) => Routes[path] = handler;

    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map(String path, HttpProcessDelegate handler) => Routes[path] = new DelegateHandler { Callback = handler };

    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map<TResult>(String path, Func<TResult> handler) => Routes[path] = new DelegateHandler { Callback = handler };

    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map<TModel, TResult>(String path, Func<TModel, TResult> handler) => Routes[path] = new DelegateHandler { Callback = handler };

    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map<T1, T2, TResult>(String path, Func<T1, T2, TResult> handler) => Routes[path] = new DelegateHandler { Callback = handler };

    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map<T1, T2, T3, TResult>(String path, Func<T1, T2, T3, TResult> handler) => Routes[path] = new DelegateHandler { Callback = handler };

    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map<T1, T2, T3, T4, TResult>(String path, Func<T1, T2, T3, T4, TResult> handler) => Routes[path] = new DelegateHandler { Callback = handler };

    /// <summary>映射控制器</summary>
    /// <typeparam name="TController"></typeparam>
    /// <param name="path"></param>
    public void MapController<TController>(String? path = null) => MapController(typeof(TController), path);

    /// <summary>映射控制器</summary>
    /// <param name="controllerType"></param>
    /// <param name="path"></param>
    public void MapController(Type controllerType, String? path = null)
    {
        if (path.IsNullOrEmpty()) path = "/" + controllerType.Name.TrimEnd("Controller");

        var path2 = path.EnsureEnd("/*");
        Routes[path2] = new ControllerHandler { ControllerType = controllerType };
    }

    /// <summary>映射静态文件</summary>
    /// <param name="path">映射路径,如 /js</param>
    /// <param name="contentPath">内容目录,如 /wwwroot/js</param>
    public void MapStaticFiles(String path, String contentPath)
    {
        path = path.EnsureEnd("/");
        var path2 = path.EnsureEnd("*");
        Routes[path2] = new StaticFilesHandler { Path = path, ContentPath = contentPath };
    }

    private readonly IDictionary<String, String> _maps = new Dictionary<String, String>(StringComparer.OrdinalIgnoreCase);
    /// <summary>匹配处理器</summary>
    /// <param name="path"></param>
    /// <param name="request"></param>
    /// <returns></returns>
    public IHttpHandler? MatchHandler(String path, HttpRequest? request)
    {
        if (Routes.TryGetValue(path, out var handler)) return handler;

        // 判断缓存
        if (_maps.TryGetValue(path, out var p) &&
            Routes.TryGetValue(p, out handler)) return handler;

        // 模糊匹配
        foreach (var item in Routes)
        {
            if (item.Key.Contains('*') && item.Key.IsMatch(path))
            {
                if (Routes.TryGetValue(item.Key, out handler))
                {
                    // 大于3段的路径不做缓存,避免动态Url引起缓存膨胀
                    if (handler is StaticFilesHandler || path.Split('/').Length <= 3) _maps[path] = item.Key;

                    return handler;
                }
            }
        }

        return null;
    }
    #endregion
}