【问题标题】:Connecting Nexmo to a Websocket fails(remote party closed the WebSocket) in .Net Core在 .Net Core 中将 Nexmo 连接到 Websocket 失败(远程方关闭了 WebSocket)
【发布时间】:2019-07-19 00:52:37
【问题描述】:

我正在尝试在进行入站呼叫时将 Nexmo 连接到网络套接字(用户拨打通过 nexmo 购买的号码并链接到应用程序)。

到目前为止,我只是在尝试这个Sample Code(它只是回应调用者所说的话)并按照“文档”Here 通过 Nexmo 连接到这个 websocket。

我成功地向 nexmo 发送了一个“连接”操作。在调用使用 Nexmo 购买的号码时,它会正确重定向到端点 (api/nexmo/socket),如使用断点时所示,但在到达 Echo 方法中的 webSocket.ReceiveAsync 时会挂断。 p>

    using System;
    using System.Net.WebSockets;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Newtonsoft.Json.Linq;

    namespace MyProject.Web.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class NexmoController : ControllerBase
        {
            private WebSocket _webSocket;

            [HttpGet("answer")]
            public IActionResult AnswerHandler()
            {
                const string host = "MY_NGROK_URL";
                const string locale = "fr-FR";

                var nccos = new JArray();
                var nccoConnect = new JObject()
                {
                    { "action", "connect" },
                    { "endpoint", new JArray(new JObject{
                            { "type", "websocket" },
                            { "uri", $"wss://{host}/api/nexmo/socket"},
                            { "content-type", "audio/l16;rate=16000"},
                            { "headers", new JObject {
                                    { "language", locale },
                                    { "callerID", "MY_NUMBER_HARDCODED_WHILE_TESTING" }
                                }
                            }
                        })
                    }
                };
                nccos.Add(nccoConnect);
                return Content(nccos.ToString(), "application/json");
            }

            [HttpPost("event")]
            public IActionResult EventHandler()
            {
                return Ok();
            }

            [HttpGet("socket")]
            public async Task GetAudio()
            {
                if (HttpContext.WebSockets.IsWebSocketRequest)
                {
                    _webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
                    await Echo(HttpContext, _webSocket);
                }
                else
                {
                    HttpContext.Response.StatusCode = 400;
                }
            }

            //Copy Paste from the Sample Code
            private async Task Echo(HttpContext context, WebSocket webSocket)
            {
                var buffer = new byte[1024 * 4];
                //Breakpoint : ReceiveAsync generates an exception
                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);
            }
        }
    }

这里是捕获的异常:

System.Net.WebSockets.WebSocketException (0x80004005):远程 一方在未完成关闭的情况下关闭了 WebSocket 连接 握手。 ---> System.Net.WebSockets.WebSocketException (0x80004005): 远程方未完成就关闭了 WebSocket 连接 亲密的握手。

更多异常:

在 System.Net.WebSockets.ManagedWebSocket.ThrowIfEOFUnexpected(Boolean throwOnPrematureClosure) 在 System.Net.WebSockets.ManagedWebSocket.EnsureBufferContainsAsync(Int32 minimumRequiredBytes, CancellationToken cancelToken, Boolean throwOnPrematureClosure) 在 System.Net.WebSockets.ManagedWebSocket.ReceiveAsyncPrivate[TWebSocketReceiveResultGetter,TWebSocketReceiveResult](Memory`1 payloadBuffer、CancellationToken、cancellationToken、 TWebSocketReceiveResultGetter resultGetter) 在 System.Net.WebSockets.ManagedWebSocket.ReceiveAsyncPrivate[TWebSocketReceiveResultGetter,TWebSocketReceiveResult](Memory`1 payloadBuffer、CancellationToken、cancellationToken、 TWebSocketReceiveResultGetter resultGetter) 在 ....Controllers.NexmoController.Echo(HttpContext 上下文, WebSocket webSocket) 中 C:...\Controllers\NexmoController.cs:行 97 在 ....Controllers.NexmoController.GetAudio() 中 C:...\Controllers\NexmoController.cs:行 68 at lambda_method(Closure, Object) at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult() 在 Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.AwaitableResultExecutor.Execute(IActionResultTypeMapper 映射器,ObjectMethodExecutor 执行器,对象控制器,Object[] 参数)在 System.Threading.Tasks.ValueTask`1.get_Result() 在 Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync() 在 Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync() 在 Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext 上下文)在 Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(状态& next, Scope& 范围, Object& 状态, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync() 在 Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter() 在 Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext 上下文)在 Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(状态和下一个, 范围&作用域、对象&状态、布尔& isCompleted)在 Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync() 在 Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
在 Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext 上下文)在 Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext 上下文)

有什么想法吗?或者我该如何解决这个问题? 我真的不明白这里有什么问题。

我还尝试检查 Websocket 的 WebSocketState,它设置为“打开”。 有关信息,我自己测试了示例代码(websocket 回显用户的输入)并且它可以工作。

【问题讨论】:

  • 你能记录你想要回显的内容吗?可能是您正在回显文本消息而不是音频。见developer.nexmo.com/voice/voice-api/guides/…
  • 我只使用音频输入,所以不是这样 :) 但最后我们发现了问题:ngrok(见下面的答案):) 仍然谢谢!

标签: c# asp.net-core websocket phone-call nexmo


【解决方案1】:

我们找到了解决方案:

  • ngrock 不适用于 websockets(并非免费),因此我们在 azure 上发布了我们的应用。
  • 我们需要在 StartUp 而不是在我们的控制器中(如sample code listed in the original post)。我们已将“Echo”方法放入 另一个类(更重要的是保持良好的结构)并将其设置为 静态的。

现在一切正常:)

澄清:ngrock 不适用于安全 websockets (wss)

【讨论】:

  • 你有链接 ngrok 限制吗?我在他们的定价ngrok.com/pricing 或文档ngrok.com/docs#websockets 中看不到任何内容
  • 执行命令时:“ngrok tls”(因为我们想使用安全的 websockets wss),我们收到以下消息:“隧道会话失败:只有专业和商业计划可以绑定 TLS 隧道。失败为“已编辑”帐户绑定 TLS 隧道。此帐户采用“免费”计划。升级到专业版或商业版:dashboard.ngrok.com/billing/planERR_NGROK_312"。切换到发布我们的应用程序有效:)
猜你喜欢
  • 2021-02-20
  • 1970-01-01
  • 2021-06-14
  • 1970-01-01
  • 2020-04-07
  • 1970-01-01
  • 2022-06-22
  • 2022-12-15
  • 2016-11-30
相关资源
最近更新 更多