本文介绍了跨起源SignalR连接停止谈判后,的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个MVC应用5服务了意见,并在Web API 2个应用程序作为服务层(.NET 4.5)。在Web API应用程序使用SignalR 2.1.2,因为它是处理POST到服务API返回的进展。这两个被部署到不同的领域,所以我设置跨起源的支持,按照 asp.net 教程文章。

I have an MVC 5 app serving up views, and a Web API 2 app as the service layer (.NET 4.5). The Web API app uses SignalR 2.1.2 to return progress as it's processing POSTs to the service API. The two are deployed to different domains, so I've set up cross origin support as per the asp.net tutorial article.

[assembly: OwinStartup(typeof (Startup))]
namespace MyApp.Service
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.Map("/signalr", map =>
            {
                //worry about locking it down to specific origin later
                map.UseCors(CorsOptions.AllowAll);
                map.RunSignalR(new HubConfiguration());
            });
            //now start the WebAPI app
            GlobalConfiguration.Configure(WebApiConfig.Register);
        }
    }
}

WebApiConfig.cs也有自己的CORS声明。

WebApiConfig.cs also contains its own CORS declaration.

namespace MyApp.Service
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            //controller invocations will come from the MVC project which is deployed to a
            //different domain, so must enable cross origin resource sharing
            config.EnableCors();
            // Web API routes
            config.MapHttpAttributeRoutes();

            //Snip other controller dependency initialisation
        }
    }
}

我定义了一个简单的轮毂类没有服务器端API(这是只允许服务器推送到客户端,而不是为客户调入)。

I've defined a simple hub class with no server-side API (it's only to allow the server to push to the clients, not for the clients to call into).

namespace MyApp.Service.Hubs
{
    [HubName("testresult")]
    public class TestResultHub : Hub
    {
    }
}

由于我打算跨域和轮毂不会暴露任何服务器端API,我没有打扰使用产生的JS代理。

Since I'm going cross-domain AND the hub is not exposing any server side API, I'm not bothering to use a generated JS proxy.

这是建立signalr枢纽连接的JS中的相关内容是:(记住这个正在从MVC应用程序,这没有任何signalr支持(除了jquery的-signalr- {}版本当然的.js担任了))

The relevant bits of the JS that set up the signalr hub connection is: (remember this is being served up from the MVC app, which does not have any signalr support (except jquery-signalr-{version}.js of course))

function TestScenarioHandler(signalrHubUrl) {
    var self = this;
//Snip irrelevant bits (mostly Knockout initialisation)

    self.signalrConnectionId = ko.observable();

    var hubConnection = $.hubConnection(signalrHubUrl, { useDefaultPath: false });

    var hubProxy = hubConnection.createHubProxy("testresult");
    hubProxy.on("progress", function(value) {
        console.log("Hooray! Got a new value from the server: " + value);
    });

    hubConnection.start()
        .done(function() {
            self.signalrConnectionId(hubConnection.id);
            console.log("Connected to signalr hub with connection id " + hubConnection.id);
        })
        .fail(function() {
            console.log("Failed to connect to signalr hub at " + hubConnection.url);
        });
}

去跨域这样,Firefox的网络流量显示(我已经证实Chrome会显示同样的事情)A到

Going cross-origin like this, Firefox network traffic shows (and I've confirmed Chrome shows the same thing) a GET to

<$c$c>http://****service.azurewebsites.net/signalr/negotiate?clientProtocol=1.5&connectionData=[{\"name\":\"testresult\"}]&_=1424419288550

请注意,名称 HubName 属性的值相匹配我的HUB类。

Notice that the name matches the value of the HubName attribute on my hub class.

这GET返回HTTP 200,响应给了我包含JSON有效载荷的的ConnectionId ConnectionToken 和一群其他领域这表明一切正常。 HTTP响应也有访问控制允许来源:头设置为与GET源于域。一切都取决于它看起来不错,但就是交通停止在那里。

This GET returns HTTP 200, the response gives me a JSON payload containing a ConnectionId, ConnectionToken, and a bunch of other fields that suggests everything's ok. The HTTP response also has the Access-Control-Allow-Origin: header set to the domain that the GET originated from. All up it looks good, except that's where the traffic stops.

但JS控制台打印无法连接到signalr在http枢纽://****service.azurewebsites.net/signalr

要验证我什么也没做太傻了,我已经添加signalr支持和基本枢纽的MVC应用程序(因此无需交叉原点),并改变了 $。hubConnection() hubConnection.createProxy()相应的调用。当我这样做,浏览器的流量显示了相同的 / signalr /谈判?... GET(显然不交叉的起源了),但随后也得到为 / signalr /连接?... / signalr /启动?... 。该JS控制台还打印出一条成功的消息。

To verify I'm not doing anything too stupid, I've added signalr support and a basic hub to the MVC app (so no cross origin required), and changed the $.hubConnection() and hubConnection.createProxy() calls accordingly. When I do that, browser traffic shows the same /signalr/negotiate?... GET (obviously not cross origin any more), but then also GETs to /signalr/connect?... and /signalr/start?.... The JS console also prints a success message.

因此​​,在总结;


  • CORS是在服务层上启用,并且signalr /洽谈 GET返回200,这似乎是一个有效的连接ID,和预期的访问控制允许来源:头。这表明,我认为服务器端CORS支持是正确的行为本身,而是signalr连接不会成功。

  • 当我重新所以signalr连接是不能跨出身,一切正常。

  • CORS is enabled on the service layer, and the signalr /negotiate GET returns 200, what appears to be a valid connection id, and the expected Access-Control-Allow-Origin: header. This suggests to me that the server-side CORS support is behaving itself correctly, but the signalr connection does not succeed.
  • When I reconfigure so the signalr connection is NOT cross origin, everything works as expected.

WTF我错过或做错了?之间的一些冲突 HttpConfiguration.EnableCors() IAppBuilder.UseCors(CorsOption)吧?

WTF am I missing or doing wrong?! Some conflict between HttpConfiguration.EnableCors() and IAppBuilder.UseCors(CorsOption) perhaps?

推荐答案

解决它。我改变了 map.UseCors(CorsOptions.AllowAll) CorsPolicy 对象传递代替,并设置 SupportsCredentials 为假,看了其他地方访问控制允许来源:* 是不符合访问控制允许的凭据:真正的

Solved it. I had changed the map.UseCors(CorsOptions.AllowAll) to pass in a CorsPolicy object instead, and set SupportsCredentials to false, having read elsewhere that Access-Control-Allow-Origin: * is incompatible with access-control-allow-credentials: true.

private static readonly Lazy<CorsOptions> SignalrCorsOptions = new Lazy<CorsOptions>(() =>
{
    return new CorsOptions
    {
        PolicyProvider = new CorsPolicyProvider
        {
            PolicyResolver = context =>
            {
                var policy = new CorsPolicy();
                policy.AllowAnyOrigin = true;
                policy.AllowAnyMethod = true;
                policy.AllowAnyHeader = true;
                policy.SupportsCredentials = false;
                return Task.FromResult(policy);
            }
        }
    };
});

public void Configuration(IAppBuilder app)
{
    app.Map("/signalr", map =>
    {
        map.UseCors(SignalrCorsOptions.Value);
        map.RunSignalR(new HubConfiguration());
     });
     //now start the WebAPI app
     GlobalConfiguration.Configure(WebApiConfig.Register);
}

设置 SupportCredentials 来真正的结果访问控制允许来源头被改写实际起源(而不是 * )和访问控制允许的凭据:真正的在响应

Setting SupportCredentials to true results in the Access-Control-Allow-Origin header being rewritten with the actual origin (not *) and access-control-allow-credentials: true in the response.

和现在的作品。

这篇关于跨起源SignalR连接停止谈判后,的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 00:34