You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#如何实现类似Discord.NET命令模式的HttpListener请求处理

实现方案

完全可以实现该需求,核心是自己实现一套特性扫描+路由映射+反射调用的逻辑,和Discord.NET命令处理的底层原理一致,不需要依赖额外的重型框架。

步骤1:定义路由特性

首先定义用于标注方法的HTTP方法特性,示例代码如下:

// 基类HTTP方法特性
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public abstract class HttpMethodAttribute : Attribute
{
    public string RoutePath { get; }
    public string HttpMethod { get; }
    protected HttpMethodAttribute(string httpMethod, string routePath)
    {
        HttpMethod = httpMethod;
        RoutePath = routePath.Trim('/');
    }
}

// POST请求特性
public class HttpPostAttribute : HttpMethodAttribute
{
    public HttpPostAttribute(string routePath) : base("POST", routePath) { }
}

// GET请求特性,可按相同逻辑扩展PUT、DELETE等
public class HttpGetAttribute : HttpMethodAttribute
{
    public HttpGetAttribute(string routePath) : base("GET", routePath) { }
}

步骤2:实现路由注册与请求处理类

该类负责扫描所有带路由特性的方法生成路由表,在HttpListener收到请求时匹配路由并调用对应处理方法:

public class HttpListenerRouter
{
    // 路由映射表:键为`请求方法:路由路径`,值为对应处理方法的元数据
    private readonly Dictionary<string, MethodInfo> _routeMap = new();
    // 业务处理类的实例
    private readonly object _handlerInstance;

    public HttpListenerRouter(object handlerInstance)
    {
        _handlerInstance = handlerInstance;
        // 构造时扫描所有路由
        ScanRoutes(handlerInstance.GetType());
    }

    // 扫描所有带路由特性的方法注册到路由表
    private void ScanRoutes(Type handlerType)
    {
        var allPublicMethods = handlerType.GetMethods(BindingFlags.Instance | BindingFlags.Public);
        foreach (var method in allPublicMethods)
        {
            var attr = method.GetCustomAttribute<HttpMethodAttribute>();
            if (attr == null) continue;
            var routeKey = $"{attr.HttpMethod}:{attr.RoutePath}";
            _routeMap[routeKey] = method;
        }
    }

    // 启动HttpListener监听
    public async Task StartAsync(string listenerPrefix)
    {
        using var listener = new HttpListener();
        listener.Prefixes.Add(listenerPrefix);
        listener.Start();
        Console.WriteLine($"监听已启动:{listenerPrefix}");

        // 循环接收请求
        while (true)
        {
            var context = await listener.GetContextAsync();
            // 异步处理请求避免阻塞
            _ = ProcessRequestAsync(context);
        }
    }

    // 处理单个请求
    private async Task ProcessRequestAsync(HttpListenerContext context)
    {
        try
        {
            var request = context.Request;
            var requestPath = request.Url.AbsolutePath.Trim('/');
            var routeKey = $"{request.HttpMethod}:{requestPath}";

            // 路由匹配失败返回404
            if (!_routeMap.TryGetValue(routeKey, out var handlerMethod))
            {
                context.Response.StatusCode = 404;
                context.Response.Close();
                return;
            }

            // 调用处理方法,可扩展此处实现参数绑定、权限校验等逻辑
            handlerMethod.Invoke(_handlerInstance, Array.Empty<object>());

            context.Response.StatusCode = 200;
            context.Response.Close();
        }
        catch (Exception ex)
        {
            context.Response.StatusCode = 500;
            using var writer = new StreamWriter(context.Response.OutputStream);
            await writer.WriteAsync(ex.Message);
            context.Response.Close();
        }
    }
}

步骤3:业务代码使用特性标注路由

和你期望的写法完全一致,直接在业务方法上标注对应特性即可:

// 业务处理类
public class MyApiHandler
{
    [HttpPost("SomeUrl")]
    public void SomeMethod()
    {
        // 你的业务逻辑
        Console.WriteLine("SomeUrl的POST请求已处理");
    }

    [HttpGet("Test/Hello")]
    public void HelloTest()
    {
        Console.WriteLine("Test/Hello的GET请求已处理");
    }
}

步骤4:启动服务

在程序入口注册业务处理类并启动监听即可:

internal class Program
{
    static async Task Main(string[] args)
    {
        var apiHandler = new MyApiHandler();
        var router = new HttpListenerRouter(apiHandler);
        // 监听本地8080端口
        await router.StartAsync("http://localhost:8080/");
    }
}

可扩展能力

如果需要更完善的功能,可以在现有基础上扩展:

  • 参数绑定:解析请求的Query、Form、Body内容,和处理方法的参数自动映射
  • 中间件逻辑:在路由匹配前后加权限校验、请求日志、异常统一处理等逻辑
  • 路由参数支持:支持/user/{id}这类带占位符的动态路由匹配

内容的提问来源于stack exchange,提问作者IdkWhatToDo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 11:27:00