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

.NET Core如何将HttpRequest推入中间件管道?跨网受限场景方案咨询

解决方案:基于WebSocket桥接的ASP.NET Core请求管道触发方案

针对你的安全规则限制(DMZ服务器禁止主动连接内网、外网服务器不得暴露用户数据),可以通过内网主动发起WebSocket长连接到DMZ服务器构建桥接,再通过手动创建HttpContext触发ASP.NET Core中间件管道的方式实现需求,同时完整保留WebSocket功能。

核心架构思路

  1. 内网服务器主动向外网DMZ服务器发起WebSocket长连接(规避DMZ主动连内网的限制)
  2. 外网服务器接收客户端的HTTP/WebSocket请求后,将请求数据序列化后通过已建立的WebSocket桥接推送给内网服务器
  3. 内网服务器手动构建HttpContext并触发中间件管道处理请求,处理完成后将响应回传给外网服务器
  4. 外网服务器把响应返回给客户端,全程不存储或暴露用户敏感数据

手动触发ASP.NET Core中间件管道的实现

ASP.NET Core的中间件管道并不依赖原生HTTP请求触发,可通过IHttpContextFactory创建自定义上下文,手动调用管道委托。

1. 定义请求/响应传输模型

用于在WebSocket桥接中传递请求和响应的核心数据:

public class ProxyRequest
{
    public string Method { get; set; }
    public string Path { get; set; }
    public string QueryString { get; set; }
    public Dictionary<string, string> Headers { get; set; }
    public string Body { get; set; }
    public bool IsWebSocketUpgrade { get; set; } // 标识是否为WebSocket升级请求
}

public class ProxyResponse
{
    public int StatusCode { get; set; }
    public Dictionary<string, string> Headers { get; set; }
    public string Body { get; set; }
}

2. 内网服务器的请求处理器

注入IHttpContextFactory和中间件管道委托,手动构建上下文并触发管道:

public class BridgeRequestProcessor
{
    private readonly IHttpContextFactory _httpContextFactory;
    private readonly RequestDelegate _requestPipeline;
    private readonly IServiceScopeFactory _scopeFactory;

    public BridgeRequestProcessor(IHttpContextFactory httpContextFactory, 
                                 RequestDelegate requestPipeline,
                                 IServiceScopeFactory scopeFactory)
    {
        _httpContextFactory = httpContextFactory;
        _requestPipeline = requestPipeline;
        _scopeFactory = scopeFactory;
    }

    public async Task<ProxyResponse> ProcessRequestAsync(ProxyRequest proxyRequest)
    {
        // 为每个请求创建独立的服务范围,保证隔离性
        using var scope = _scopeFactory.CreateScope();
        var httpContext = _httpContextFactory.Create(scope.ServiceProvider);

        // 配置请求属性
        httpContext.Request.Method = proxyRequest.Method;
        httpContext.Request.Path = proxyRequest.Path;
        httpContext.Request.QueryString = new QueryString(proxyRequest.QueryString);

        // 复制请求头
        foreach (var header in proxyRequest.Headers)
        {
            httpContext.Request.Headers.TryAdd(header.Key, header.Value);
        }

        // 写入请求正文
        if (!string.IsNullOrEmpty(proxyRequest.Body))
        {
            var bodyBytes = Encoding.UTF8.GetBytes(proxyRequest.Body);
            await httpContext.Request.Body.WriteAsync(bodyBytes);
            httpContext.Request.Body.Position = 0;
        }

        // 手动触发中间件管道
        await _requestPipeline(httpContext);

        // 读取并封装响应
        var response = new ProxyResponse
        {
            StatusCode = (int)httpContext.Response.StatusCode,
            Headers = httpContext.Response.Headers.ToDictionary(h => h.Key, h => h.Value.ToString())
        };

        httpContext.Response.Body.Position = 0;
        using var reader = new StreamReader(httpContext.Response.Body);
        response.Body = await reader.ReadToEndAsync();

        return response;
    }
}

3. WebSocket请求的透明转发

对于WebSocket请求,无需经过中间件管道,直接在外网和内网服务器之间转发WebSocket帧:

// 外网服务器:处理客户端WebSocket连接并转发到桥接连接
public async Task RelayWebSocketAsync(WebSocket clientSocket, WebSocket bridgeSocket, CancellationToken ct)
{
    var buffer = new byte[4096];
    var clientReceive = clientSocket.ReceiveAsync(new ArraySegment<byte>(buffer), ct);
    var bridgeReceive = bridgeSocket.ReceiveAsync(new ArraySegment<byte>(buffer), ct);

    while (!ct.IsCancellationRequested && clientSocket.State == WebSocketState.Open && bridgeSocket.State == WebSocketState.Open)
    {
        var completed = await Task.WhenAny(clientReceive, bridgeReceive);
        if (completed == clientReceive)
        {
            var result = await clientReceive;
            await bridgeSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, ct);
            clientReceive = clientSocket.ReceiveAsync(new ArraySegment<byte>(buffer), ct);
        }
        else
        {
            var result = await bridgeReceive;
            await clientSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, ct);
            bridgeReceive = bridgeSocket.ReceiveAsync(new ArraySegment<byte>(buffer), ct);
        }
    }
}

通用优化建议

  • 序列化优化:用Protobuf替代JSON序列化请求/响应数据,提升传输性能和压缩率
  • 连接保活与重连:在内网服务器中实现WebSocket连接的自动重连机制,配合心跳包维持长连接
  • 请求路由:在外网服务器中添加简单的路由逻辑,将不同路径的请求转发到对应内网服务的桥接连接
  • 日志与监控:在桥接两端添加请求日志、连接状态监控,便于排查问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 17:17:44