反向代理/跨域的 SignalR 连接问题

SignalR connectivity issue with reverse proxy / cross domains

我在 Azure(公司服务应用程序)的 Owin Web API 应用程序 运行 中托管了一个 SignalR 服务器和 运行。从一个单独的 Web 应用程序,假设应用程序 A(非 Azure)我正在使用 javascript 生成的代理连接到 SignalR:

CompanyServiceBaseUrl 设置为我的站点 url:(例如 "http:// mysite/companyservice")

    <script src="@Url.Content(CompanyServiceBaseUrl + "/Scripts/jquery.signalR-2.2.0.js")"></script>
    <script src="@Url.Content(CompanyServiceBaseUrl + "/signalr/hubs")" type="text/javascript"></script>

    <script type="text/javascript">
    var hub = $.connection.perform;

    hub.client.onToast = function () {
        $("#copyOrganizationSuccessAlert").show();
    };

    $(document).ready(function() {
        var event = document.createEvent('Event');
        event.initEvent('onOrganizationLock', true, true);

        onOrganizationLockEvent = function() {
            document.dispatchEvent(event);
        };

        hub.client.onOrganizationLock = onOrganizationLockEvent;
    });

    $.connection.hub.start().done(function () {
        hub.server.joinGroup(perform.company.application.clientId);
    });
</script>

这是我在客户端生成的文件夹结构:

当我在本地测试时,SignalR 连接工作正常,但当我在 Azure 托管的环境中测试时,连接失败。

SignalR 协商请求(在 App A 和 CompanyService 之间):

http://<mysiteurl>/signalr/negotiate(请注意 URL:

中缺少 companyservice

应该是:

http://<mysiteurl>/companyservice/signalr/negotiate

这里是反向代理规则:

   <rule name="companyservice" stopProcessing="true"> 
      <match url="^companyservice/(.*)" /> 
      <conditions> 
        <add input="{CACHE_URL}" pattern="^(https?)://" /> 
      </conditions> 
      <action type="Rewrite" url="https://myazuresite.azurewebsites.net/{R:1}" /> 
      <serverVariables> 
        <set name="HTTP_ACCEPT_ENCODING" value="" /> 
      </serverVariables> 
    </rule> 
  </rules>

问题:

为什么我的客户端 connection.Url 在使用反向代理测试我的 Azure 站点时显示为“/signalr”而不是“/companyservice/signalr”?

最后,看看这个报告的 SignalR 问题,看起来他遇到了非常相似的事情:

SignalR doesn't work behind a Reverse Proxy

但我想了解他的意思:

"如果我使用反向代理规则(扫描和替换)并设置 "Url":"/NorthboundWebApiClient/signalr" 一切正常。

我已经尝试建立一个连接 with and without generated proxies 手动指定我的连接 url var connection = $.hubConnection('/companyservice/signalr', {useDefaultPath: false});,在客户端配置 CORS 但没有成功。

这里有一个相关的 post 有跨域问题:

How do I get a SignalR hub connection to work cross-domain?

四个月后,一位同事提出了一个完美的解决方案。他的想法是创建一个自定义 OwinMiddleware,将丢失的 Azure 虚拟目录添加到路径中以防丢失。像这样:

public class SignalRvDirMiddleware : OwinMiddleware
{
   public SignalRvDirMiddleware(OwinMiddleware next)
    : base(next)
   { }

   public override async Task Invoke(IOwinContext context)
   {
       var vdir = new PathString("/companyservice");
       PathString path = context.Request.PathBase;
       if (!path.StartsWithSegments(vdir))
       {
          context.Request.PathBase = vdir + path;
       }
       await Next.Invoke(context);
    }
 }

然后将其连接到 Startup.cs 上的 Owin 配置方法中:

    public void Configuration(IAppBuilder appBuilder)
    {
        // Branch the pipeline here for requests that start with "/signalr"
        appBuilder.Map("/signalr", map =>
        {
            map.Use<SignalRvDirMiddleware>();
            map.RunSignalR(hubConfiguration);
        });
     }

感谢我的同事 Jake S。