c# - 在 .Net Core 中将 Nexmo 连接到 Websocket 失败(远程方关闭了 WebSocket)
问题描述
我正在尝试在进行入站呼叫时将Nexmo连接到 Web 套接字(用户拨打使用 nexmo 购买的号码并链接到应用程序)。
到目前为止,我只是在尝试这个示例代码(它只是回应调用者所说的话)并按照“文档” Here之后通过 Nexmo 连接到这个 websocket 。
我成功地向 nexmo 发送了一个动作“连接”。在调用使用 Nexmo 购买的号码时,它会正确重定向到端点 ( ),如使用断点时所示,但在 Echo 方法中到达webSocket.ReceiveAsyncapi/nexmo/socket
时它会挂断。
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, CancellationTokencancellationToken, Boolean throwOnPrematureClosure) 在 System.Net.WebSockets.ManagedWebSocket.ReceiveAsyncPrivate[TWebSocketReceiveResultGetter,TWebSocketReceiveResult](
Memory`1
在 System.Net.WebSockets.ManagedWebSocket.ReceiveAsyncPrivate[TWebSocketReceiveResultGetter,TWebSocketReceiveResult](Memory`1
payloadBuffer, CancellationToken cancelToken, TWebSocketReceiveResultGetter resultGetter) at ....Controllers.NexmoController.Echo(HttpContext context, WebSocket webSocket) in C:...\Controllers\NexmoController.cs:line 97 at ....Controllers.NexmoController.GetAudio () 在 C:...\Controllers\NexmoController.cs:line 68 at lambda_method(Closure , Object) at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult() at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.AwaitableResultExecutor .Execute(IActionResultTypeMapper 映射器,ObjectMethodExecutor 执行器,对象控制器,Object[] 参数)在 Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync() 的 System.Threading.Tasks.ValueTask`1.get_Result() 在 Microsoft.AspNetCore。 Mvc.内部。ControllerActionInvoker.InvokeNextActionFilterAsync() 在 Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) 在 Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) 在 Microsoft.AspNetCore .Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync() 在 Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter() 在 Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context) 在 Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync() 的 Microsoft.AspNetCore.Mvc.Internal 的 .Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)。ResourceInvoker.InvokeAsync()
在 Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) 在 Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware .Invoke(HttpContext 上下文)
有什么想法吗?或者我该如何解决这个问题?我真的不明白这里有什么问题。
我还尝试检查 Websocket 的 WebSocketState 并将其设置为“打开”。有关信息,我自己测试了示例代码(websocket 回显用户的输入)并且它可以工作。
解决方案
我们找到了解决方案:
- ngrock不适用于 websockets(不是免费的),所以我们在 azure 上发布了我们的应用程序。
- 我们需要在StartUp中而不是在我们的控制器中实例化 websocket(如原始帖子中列出的示例代码)。我们将“Echo”方法放在另一个类中(为了保持良好的结构更是如此)并将其设置为静态。
现在一切正常:)
澄清:ngrock不适用于安全的 websockets (wss)
推荐阅读
- reactjs - 如何在 React JS 中使字符串的特定部分变为粗体?
- javascript - 不和谐的警报命令。date.hours() 中的问题
- fable-f# - 单击按钮后处理文本区域的内容
- python - SQLALCHEMY 删除关联对象不会从父子节点中删除
- javascript - 删除按钮删除所有的孩子,而不是只有一个有键
- php - wp_enqueue_style 在子主题中不起作用
- c# - 在将包添加到内部提要/存储库之前扫描包
- python-3.x - 是否可以通过电子邮件发送可执行的 python 程序以在 3rd 方计算机上执行
- r - 错误:在 rstudio 中安装 tinytex (tinytex::install_tinytex())
- html - 奇怪的移动 CSS 行为