【问题标题】:SignalR (5.0.6) not working on IIS, works locallySignalR (5.0.6) 不在 IIS 上工作,在本地工作
【发布时间】:2021-08-04 16:06:13
【问题描述】:

我正在尝试通过 signalR 连接到 Web 套接字连接。它在本地运行良好。旧版本甚至可以很好地部署在同一台机器上(同时)。这很重要,因为服务器 (2) 位于 AWS 负载均衡器之后。

错误信息如下:

与“wss://stg-api.guestbell.com/hubs/main?role-type=1&access_token=eyJhbG...”的 WebSocket 连接失败

当我在 Chrome 上打开网络 WS 部分时,我看到状态为“已完成”并且没有其他错误。恕我直言,这很奇怪,因为我期望 401/500... 或者当它不起作用时类似的东西。

代码: 前端:

connection = new HubConnectionBuilder()
    .withUrl(
      Config.apiUrl +
        Config.signalRMainPath +
        '?role-type=' +
        RoleTypeEnum.Guest,
      {
        accessTokenFactory: () => store.getState().oidc.user?.access_token,
        transport: HttpTransportType.WebSockets,
        // I've tried various combinations of these
        /*skipNegotiation: true,
        withCredentials: true,*/
      }
    )
    .withAutomaticReconnect({
      nextRetryDelayInMilliseconds: retryContext => {
        return Math.random() * 10000 + 5000;
      },
    })
    .build();
...
await connection.start();

后端:

// Configure services
var signalRBuilder = services.AddSignalR();
// Configure
app.UseCors("CorsPolicy");
if (env.IsDevelopment()) {
  app.UseSimulatedLatency(
    min: TimeSpan.FromMilliseconds(100),
    max: TimeSpan.FromMilliseconds(300)
  );
} else {
  app.UseHsts();
  app.UseForwardedHeaders();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseDefaultFiles();
app.UseStaticFiles(new StaticFileOptions {
  OnPrepareResponse = ctx => {
    const int durationInSeconds = 60 * 60 * 24 * 30;
    ctx.Context.Response.Headers[HeaderNames.CacheControl] =
      "public,max-age=" + durationInSeconds;
  }
});
app.UseSignalRQueryStringAuth();

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints => {
  endpoints.MapHub < SignalRMainCore > ("/hubs/main");
  endpoints.MapHealthChecks("/health");
  endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
});

我不知道我的问题在哪里?

我正在使用:

"@microsoft/signalr": "^5.0.6"

其他相关信息:

机器上的Dotnet版本:


C:\Users\Administrator>dotnet --info
.NET SDK (reflecting any global.json):
 Version:   5.0.203
 Commit:    383637d63f

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.17763
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\5.0.203\

Host (useful for support):
  Version: 5.0.6
  Commit:  478b2f8c0e

.NET SDKs installed:
  5.0.203 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.6 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

编辑:

我注意到了一些奇怪的事情。当我复制 websockets URL 并将其粘贴到浏览器(将 wss 替换为 https)时,我得到:

Cannot change transports mid-connection

在它起作用的页面上(有道理,错误显然来自信号 r)

但是当我对不起作用的页面执行相同操作时,我得到了标准的 IIS 404:

现在这似乎很可疑……就像 IIS 以某种方式劫持了 HTTP 管道。奇怪的是相同的代码在我的本地机器上的 IIS 上工作。既表达又恰当。

可能是红鲱鱼......我不知道

编辑 2: 额外的小信息,协商工作,返回 200 和此响应:

{"negotiateVersion":1,"connectionId":"_5nQwxYYBAczXdW77JAGeQ","connectionToken":"GizQot1b0Gq2epsiM4BA3A","availableTransports":[{"transport":"WebSockets","transferFormats":["Text","Binary"]},{"transport":"ServerSentEvents","transferFormats":["Text"]},{"transport":"LongPolling","transferFormats":["Text","Binary"]}]}

这与服务器的设置方式一致。

【问题讨论】:

  • 您是否在开发工具中检查过请求以查看其内容?您是否在 IIS 中安装了 WebSocket 支持?证书是否受信任?
  • 是的,还有另一个站点在这些机器上具有完全相同的设置并且它在那里工作(它不是完全相同的代码,它是一个旧版本,但主要区别是从 dotnet 3.1 更新到5.0.6).
  • 请注意我的编辑,也许有些事情会响起。谢谢@fredrik!
  • 猜测 Frederik 的回答可能是正确的。默认情况下,IIS 主机通常没有启用 web-sockets 协议。确保您的 IIS 配置正确,请参阅 IIS/IIS Express SupportWebsockets Fundamentals
  • 绝对启用,就像我提到的那样,它可以在同一个 IIS 上托管的不同网站上运行

标签: c# asp.net-core .net-core signalr


【解决方案1】:

我花了 2 天时间... 不敢相信我们有时所做的工作。无论如何,这就是故事。

作为升级的一部分,我还将 IdentityServer 更新到最新版本。我几乎不知道他们稍微改变了生成访问令牌的算法。事实上,这种变化导致访问令牌的长度增加了大约 100 个字符。

可以理解,这没什么大不了的,因此在任何明显的迁移指南中都没有提到。

但是,使用 signalR,您可以在查询字符串中传递 accessToken。一般来说没什么大不了的,当然在 localhost 也没什么大不了的。但是,默认情况下,IIS 对 qs 长度有限制......我相信你知道我要去哪里。

我的第一次编辑实际上是一个很好的线索。它给了我 404 没有明显的原因。然后我分叉了signalR的默认示例,开始一一添加。然后通过身份验证,它停止工作。花了几个小时才发现访问令牌实际上是罪魁祸首。

无论如何,web.config 中的一个简单更改解决了这个问题:

  ...
  <system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxQueryString="8192" />
      </requestFiltering>
    </security>
    ...
  <system.webServer>
  ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-03
    • 2013-11-14
    • 1970-01-01
    • 2019-10-22
    • 2012-10-31
    相关资源
    最近更新 更多