创建WebSocketProxy以在Asp.net Core 6中实现嵌入NOVNC时出现问题

问题描述 投票:0回答:1

我想将 iframe 中的 novnc 控制台嵌入到 .net Web 应用程序中。我的 openstack 配置为接收 http 请求,而我的 Web 应用程序发送 https 请求。 当我使用 iframe 在 asp.net Web 应用程序中显示我的 novnc 控制台时,控制台将 WSS 请求发送到我的服务器,但 openstack Horizon 接受 WS 请求,因此我创建了一个中间件来将请求从 https 转换为 http & WSS 转换为 WS但它不起作用,我不知道问题是什么,我的控制台显示但连接立即关闭。

我处理http请求的反向代理是:


namespace ReverseProxyApplication
{
    public class ReverseProxyMiddleware
    {
        private static readonly HttpClient _httpClient = new HttpClient();


        private readonly RequestDelegate _nextMiddleware;

        public ReverseProxyMiddleware(RequestDelegate nextMiddleware)
        {
            _nextMiddleware = nextMiddleware;
        }

        public async Task Invoke(HttpContext context)
        {
            var targetUri = BuildTargetUri(context.Request);

            if (targetUri != null)
            {

            
                var targetRequestMessage = CreateTargetMessage(context, targetUri);

                using (var responseMessage = await _httpClient.SendAsync(targetRequestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
                {
                    context.Response.StatusCode = (int)responseMessage.StatusCode;
                    CopyFromTargetResponseHeaders(context, responseMessage);
                    await responseMessage.Content.CopyToAsync(context.Response.Body);
                }
              
                return;
            }

            await _nextMiddleware(context);
        }

        private HttpRequestMessage CreateTargetMessage(HttpContext context, Uri targetUri)
        {
            var requestMessage = new HttpRequestMessage();
            CopyFromOriginalRequestContentAndHeaders(context, requestMessage);

            requestMessage.RequestUri = targetUri;
            requestMessage.Headers.Host = targetUri.Host;
            requestMessage.Method = GetMethod(context.Request.Method);

            return requestMessage;
        }

        private void CopyFromOriginalRequestContentAndHeaders(HttpContext context, HttpRequestMessage requestMessage)
        {
            var requestMethod = context.Request.Method;

            if (!HttpMethods.IsGet(requestMethod) &&
              !HttpMethods.IsHead(requestMethod) &&
              !HttpMethods.IsDelete(requestMethod) &&
              !HttpMethods.IsTrace(requestMethod))
            {
                var streamContent = new StreamContent(context.Request.Body);
                requestMessage.Content = streamContent;
            }

            foreach (var header in context.Request.Headers)
            {
                requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
            }
        }

        private void CopyFromTargetResponseHeaders(HttpContext context, HttpResponseMessage responseMessage)
        {
            foreach (var header in responseMessage.Headers)
            {
                context.Response.Headers[header.Key] = header.Value.ToArray();
            }

            foreach (var header in responseMessage.Content.Headers)
            {
                context.Response.Headers[header.Key] = header.Value.ToArray();
            }
            context.Response.Headers.Remove("transfer-encoding");
        }
        private static HttpMethod GetMethod(string method)
        {
            if (HttpMethods.IsDelete(method)) return HttpMethod.Delete;
            if (HttpMethods.IsGet(method)) return HttpMethod.Get;
            if (HttpMethods.IsHead(method)) return HttpMethod.Head;
            if (HttpMethods.IsOptions(method)) return HttpMethod.Options;
            if (HttpMethods.IsPost(method)) return HttpMethod.Post;
            if (HttpMethods.IsPut(method)) return HttpMethod.Put;
            if (HttpMethods.IsTrace(method)) return HttpMethod.Trace;
            return new HttpMethod(method);
        }

        private Uri BuildTargetUri(HttpRequest request)
        {
            Uri targetUri = null;

            if (request.Path.StartsWithSegments("/horizon", out var remainingPath))
            {
                targetUri = new Uri("http://192.168.66.11:6080" + remainingPath);
            }



            return targetUri;
        }
    }
}

和我的网络套接字中间件

public class WebSocketMiddleware
{
    private static ConcurrentDictionary<string, WebSocket> _sockets = new ConcurrentDictionary<string, WebSocket>();

    private readonly RequestDelegate _next;

    public WebSocketMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        if (!context.WebSockets.IsWebSocketRequest)
        {
            await _next.Invoke(context);
            return;
        }
        var buffer = new ArraySegment<byte>(new byte[8192]);
        Uri targetUri = new Uri("ws://192.168.66.11:6080/" + context.Request.QueryString.Value);
        ClientWebSocket _websocketClient = new ClientWebSocket();

        await _websocketClient.ConnectAsync(targetUri, CancellationToken.None);
        // if (_websocketClient.State == WebSocketState.Open)
        // {
        //     // await _websocketClient.SendAsync(buffer, WebSocketMessageType.Binary, true, CancellationToken.None);
        //     var result = await _websocketClient.ReceiveAsync(buffer, CancellationToken.None);

        //     if (result.MessageType == WebSocketMessageType.Close)
        //     {
        //         await _websocketClient.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);

        //     }
        // }

        CancellationToken ct = context.RequestAborted;
        WebSocket currentSocket = await context.WebSockets.AcceptWebSocketAsync();

        var socketId = Guid.NewGuid().ToString();

        _sockets.TryAdd(socketId, currentSocket);

        foreach (var socket in _sockets)
        {
            if (socket.Value.State != WebSocketState.Open)
            {
                continue;
            }

            await SendStringAsync(socket.Value, _websocketClient, buffer, ct);
        }







        while (true)
        {
            if (ct.IsCancellationRequested)
            {
                break;
            }

            var response = await ReceiveStringAsync(currentSocket, _websocketClient, context, ct);
            if (response != null)
            {
                if (currentSocket.State != WebSocketState.Open)
                {
                    break;
                }
                //continue;
                foreach (var socket in _sockets)
                {
                    if (socket.Value.State != WebSocketState.Open)
                    {
                        continue;
                    }

                    await SendStringAsync(socket.Value, _websocketClient, response, ct);
                }

            }



        }

        WebSocket dummy;
        _sockets.TryRemove(socketId, out dummy);

        await currentSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", ct);
        currentSocket.Dispose();
    }

    private static Task SendStringAsync(WebSocket socket, ClientWebSocket _websocketClient, ArraySegment<byte> data, CancellationToken ct = default(CancellationToken))
    {
        //var buffer = Encoding.UTF8.GetBytes(data);
        var segment = new ArraySegment<byte>(new byte[8192]);
        if (_websocketClient.State == WebSocketState.Open)
        {

            _websocketClient.ReceiveAsync(segment, CancellationToken.None);
            //_websocketClient.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None);


        }
        return socket.SendAsync(segment, WebSocketMessageType.Binary, true, ct);
    }

    private static async Task<ArraySegment<byte>> ReceiveStringAsync(WebSocket socket, ClientWebSocket _websocketClient, HttpContext context, CancellationToken ct = default(CancellationToken))
    {
        var buffer = new ArraySegment<byte>(new byte[8192]);

        WebSocketReceiveResult result;
        do
        {
            ct.ThrowIfCancellationRequested();

            result = await socket.ReceiveAsync(buffer, ct);

        } while (!result.EndOfMessage);

        // Uri targetUri = new Uri("ws://192.168.66.11:6080/" + context.Request.QueryString.Value);
        //ClientWebSocket _websocketClient = new ClientWebSocket();
        //await _websocketClient.ConnectAsync(targetUri, CancellationToken.None);
        if (_websocketClient.State == WebSocketState.Open)
        {
            bool hasAllZeroes = buffer.All(singleByte => singleByte == 0);
            if (!hasAllZeroes)
                await _websocketClient.SendAsync(buffer, WebSocketMessageType.Binary, true, CancellationToken.None);
            //var myresult = await _websocketClient.ReceiveAsync(buffer, CancellationToken.None);



        }

        return buffer == new ArraySegment<byte>(new byte[8192]) ? null : buffer;

    }
}

当我加载页面时,这是我的 wss 请求

novnc console in i frame

js errors

wss request to middle ware .

asp.net-mvc asp.net-core websocket openstack novnc
1个回答
0
投票

使用 YARP 中的 IHttpForwarder https://microsoft.github.io/reverse-proxy/articles/direct-forwarding.html。它处理 websocket、grpc 等。

© www.soinside.com 2019 - 2024. All rights reserved.