【问题标题】:Is Asp.net Core Websocket compatible with linux/docker?Asp.net Core Websocket 是否与 linux/docker 兼容?
【发布时间】:2018-06-22 10:02:36
【问题描述】:

我用 VS2017 创建了一个 Asp.net Core 2.1 项目,并配置了一个 linux Docker 容器。

我想实现 websockets,所以我完全遵循了这个文档:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/websockets?view=aspnetcore-2.1

如果我将 ASP.net 项目设置为启动项目(使用 IIS express),那么一切正常,我可以使用 chrome Smart Websocket Client 扩展名连接到 websocket 端点。

但是,如果我将 Docker-compose 项目设置为启动项目(因此应用程序在 linux 容器上运行),那么当我尝试连接到 websocket 端点时,服务器上会出现异常。

知道为什么这适用于 IIS express 而不是 Docker linux 容器吗?

这是一个例外:

Failed to authenticate HTTPS connection.
System.IO.IOException: The handshake failed due to an unexpected packet format.
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Security.SslState.ThrowIfExceptional()
at System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)
at System.Net.Security.SslStream.EndAuthenticateAsServer(IAsyncResult asyncResult)
at System.Net.Security.SslStream.<>c.<AuthenticateAsServerAsync>b__51_1(IAsyncResult iar)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionAdapter.InnerOnConnectionAsync(ConnectionAdapterContext context)
HttpsConnectionAdapter:Debug: Failed to authenticate HTTPS connection.

System.IO.IOException: The handshake failed due to an unexpected packet format.
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Security.SslState.ThrowIfExceptional()
at System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)
at System.Net.Security.SslStream.EndAuthenticateAsServer(IAsyncResult asyncResult)
at System.Net.Security.SslStream.<>c.<AuthenticateAsServerAsync>b__51_1(IAsyncResult iar)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionAdapter.InnerOnConnectionAsync(ConnectionAdapterContext context)

更新 1:

以下是有关我如何创建项目的更多详细信息:

在 VS2017 中:

  • 文件 -> 新项目 -> ASP.NET Core Web 应用程序
  • 选择核心 2.1
  • 选择 API
  • 在 Linux 操作系统中启用 Docker 支持
  • 点击确定

在 Configure(...) 的 Startup.cs 中添加以下代码:

var webSocketOptions = new WebSocketOptions()
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
    ReceiveBufferSize = 4 * 1024
};
app.UseWebSockets(webSocketOptions);
app.Use(async (context, next) =>
{
    if (context.Request.Path == "/ws")
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
            await Echo(context, webSocket);
        }
        else
        {
            context.Response.StatusCode = 400;
        }
    }
    else
    {
        await next();
    }

});

在 Startup.cs 我添加以下函数

private async Task Echo(HttpContext context, WebSocket webSocket)
{
    var buffer = new byte[1024 * 4];
    WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    while (!result.CloseStatus.HasValue)
    {
        await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);

        result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    }
    await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}
  • 当我启动应用程序 (iis express) 时,经典 API 使用 HTTP 工作,Websocket 也是如此。
  • 当我启动 docker 版本时,经典 API 使用 HTTP 而不是 websocket 工作(返回上述错误)。 -> 另一个我必须调查的错误。

我尝试在项目调试属性中激活 SSL:

  • 然后当我启动应用程序 (iis express) 时,经典 API 使用 HTTPS 工作,但 websocket 挂起(服务器端没有收到任何内容)。
  • 当我启动 docker 版本时,经典 API 使用 HTTPS 而不是 websocket 工作(返回上述错误)。

【问题讨论】:

  • 异常显示 HTTPS 连接失败,这与 WebSocket 没有紧密联系。您可以检查它是否已报告给 Microsoft,github.com/dotnet/corefx/issues 或在那里发布一个包含更多详细信息的新问题。
  • 嗨@LexLi,我在原帖中添加了更多细节。我不知道为什么这是一个 HTTPS 错误,因为我的项目没有使用 SSL,我使用经典的 HTTP 端口来调用 web api 和 websocket。

标签: c# linux docker asp.net-core websocket


【解决方案1】:

好的,我刚刚发现发生了什么。

最初的问题是,即使项目未配置为使用 SSL(在 Project->Properties->Debug->Enable SSL 中),docker 容器仍然会使用 HTTPs。因此,您必须使用容器的 HTTPS 端口(可在 docker-compose.override.yml 中查看)并使用 wss:// 而不是 ws://

如果您尝试使用 HTTP 端口,则容器应用程序将尝试重定向到 HTTPS 端口。这就是发生在我身上的事情,导致 HTTPS 错误。

关于我开篇文章的“更多详细信息”部分,我没有使用 wss:// 而是使用 ws://,这就是 IIS Express 应用程序没有收到任何内容并且 Docker 应用程序仍然显示错误的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-12
    • 2018-12-07
    • 2021-06-25
    • 2018-06-21
    • 1970-01-01
    • 2015-08-04
    • 1970-01-01
    相关资源
    最近更新 更多