我正在尝试连接到我的服务器 (.NET) 上使用 SignalR 建立的 websocket。
我的客户端(JavaScript)开始协商,获得带有connectionId、connectionToken等的响应,但随后无法与任何可用的传输方法连接。
我得到的最后一个调试跟踪是这样的:
[2022-11-17T10:21:02.093Z] Debug: HubConnection failed to start successfully because of error 'Error: Unable to connect to the server with any of the available transports. WebSockets failed: Error: There was an error with the transport. ServerSentEvents failed: Error: Error occurred LongPolling failed: Error'.
我的服务器代码:
启动.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace Sample
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => options.EnableEndpointRouting = false).SetCompatibilityVersion(CompatibilityVersion.Version_3_0).AddNewtonsoftJson();
services.AddSignalR().AddNewtonsoftJsonProtocol(opt => {
opt.PayloadSerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
{
builder.WithOrigins("http://localhost:8080", "http://127.0.0.1:8080")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
}));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseFileServer();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseCors("MyPolicy");
app.UseMvc();
app.UseRouting();
app.UseEndpoints(routes =>
{
routes.MapHub<Controllers.DesignAutomationHub>("/api/signalr/designautomation");
});
}
}
}
控制器:
using Autodesk.Forge;
using Autodesk.Forge.DesignAutomation;
using Autodesk.Forge.DesignAutomation.Model;
using Autodesk.Forge.Model;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Sample.Controllers
{
[ApiController]
public class ServiceController : Controller
{
// Design Automation v3 API
DesignAutomationClient _designAutomation;
// Used to access the application folder (temp location for files & bundles)
private IWebHostEnvironment _env;
// used to access the SignalR Hub
private IHubContext<DesignAutomationHub> _hubContext;
public ServiceController(IWebHostEnvironment env, IHubContext<DesignAutomationHub> hubContext, DesignAutomationClient api)
{
_designAutomation = api;
_env = env;
_hubContext = hubContext;
}
}
/// <summary>
/// Class uses for SignalR
/// </summary>
public class DesignAutomationHub : Microsoft.AspNetCore.SignalR.Hub
{
public string GetConnectionId() { return Context.ConnectionId; }
}
}
客户:
var connection;
var connectionId;
function startConnection(onReady) {
if (connection && connection.connectionState) {
if (onReady) onReady();
return;
}
connection = new signalR.HubConnectionBuilder()
.withUrl(
"http://<SERVERADRESS>/api/signalr/designautomation"
)
.configureLogging(signalR.LogLevel.Trace)
.build();
connection.start().then(function () {
connection.invoke("getConnectionId").then(function (id) {
connectionId = id;
if (onReady) onReady();
});
});
connection.on("downloadResult", function (url) {
console.log('<a href="' + url + '">Download result file here</a>');
});
connection.on("onComplete", function (message) {
console.log(message);
});
}
我在一台机器上使用服务器和客户端进行了本地测试,一切正常。但自从部署测试以来,我收到了错误。 (Websocket 在服务器上激活。)
Postman 也可以建立与 websocket 的连接,只是我的客户端失败了。
我将不胜感激任何形式的帮助。预先感谢!
编辑: 我还尝试通过(here)描述的 SignalR 客户端替代方案连接到 SignalR。
async function connectToWebsocket(negotiations) {
let token = encodeURIComponent(negotiations.connectionToken);
let wssPath = `ws://<SERVERADRESS>/api/signalr/designautomation?id=${token}`;
let ws = new WebSocket(wssPath);
console.log(ws);
}
async function connectToSignalR() {
$.ajax({
url: "<SERVERADRESS>/api/signalr/designautomation/negotiate?negotiateVersion=1",
contentType: "application/json",
dataType: "json",
headers: { "Access-Control-Allow-Origin": "*" },
type: "POST",
success: function (res) {
console.log(res);
connectToWebsocket(res);
},
error: function (error) {
console.log(error);
},
});
}
结果还是一样。我收到了协商的响应,但无法连接到 websocket。
作为附加信息。我的“服务器”是 Azure-VM 上的 iis-express,具有通过 ngrok 转发的地址。
另一个编辑: 我关于使用 SignalR 的整个案例是运行一个 websocket 连接,autodesk-forge 服务器可以在完成我提交的任务时回调该连接,让他们知道下一个任务是什么。 我添加了Tag,也许这个方向的人遇到了同样的问题并可以给出提示。
还有另一个编辑: 我现在还尝试使用我能找到的最简单的示例(来自微软的 chatapp 示例)连接到远程服务器。 还是同样的问题。我在这里添加了整个控制台输出: 我也很好奇我的 CORS 是否有问题。 但它的定义如每个工作示例中所述......
问题是由 ngrok 和可能的 CORS 引起的(如控制台输出中所述)。
在正确的方向推动之后,我尝试了另一个工具(Conveyor - VS Extension)将本地主机转发到网络。从远程客户端连接到 websocket 或任何其他传输方法绝对没有问题。
因此,对于遇到同样问题的任何人,尝试在 iis-express 中调试使用 ngrok 转发的 websocket 连接并收到 CORS 错误,请改用 Conveyor。 只要您不知道如何配置 ngroks CORS 处理(“http --host-header=rewrite”就不起作用)。
如果您知道如何配置 ngroks CORS 处理,我很乐意在评论中阅读它。
我遇到了同样的问题,但在 iis 中启用 Web 套接字功能后,它起作用了。