Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issues with SignalR and Cross Domain requests in Chrome 27

EDIT: This is apparently only a problem in Chrome, it works fine in FF and IE

Chrome version: 27.0.1453.116

I've got a simple JS/HTML site on localhost:13371, and I'm trying to access a SignalR hub at localhost:13371.

Whenever the request is made, I get the following error:

XMLHttpRequest cannot load http://localhost:13370/signalr/hubs/negotiate?_=1372338722032. Origin http://localhost:13371 is not allowed by Access-Control-Allow-Origin.

What I've tried already:

  • Enabling Cross-Domain on SignalR on Application_Start:

    RouteTable.Routes.MapHubs(new HubConfiguration { EnableCrossDomain = true });
    
  • Enabling Cross-Domain in the Web.Config of the SignalR server:

    <system.webServer>
       <httpProtocol>
         <customHeaders>
           <clear />
           <add name="Access-Control-Allow-Origin" value="*" />
           <add name="Access-Control-Allow-Methods" value="*" />
           <add name="Access-Control-Allow-Headers" value="*" />
         </customHeaders>
       </httpProtocol>
    </system.webServer>
    
  • Setting up the connection url on signalr's hub in JavaScript:

    $.connection.hub.url = 'http://localhost:13370/signalr/hubs';
    
  • Enabling CORS in jQuery:

    $.support.cors = true;
    
  • Setting response header manually in Application_BeginRequest:

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
    
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        {
            //These headers are handling the "pre-flight" OPTIONS call sent by the browser
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "*");
            HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
            HttpContext.Current.Response.End();
        }
    }
    

None of the above, nor any combination of the above has worked.

Additional information:

  • Both sites are running in IIS on Windows 7
  • The SignalR site is running on port 13370 as part of a MVC 4 site under .NET 4.0.
  • The JS/HTML site is a simple webserver on port 13371, no managed code at all.
  • The SignalR site will definitely respond to direct requests from the browser for the resource in question.
  • SignalR version is 1.1.2
like image 470
Ben Lesh Avatar asked Jun 27 '13 13:06

Ben Lesh


2 Answers

EDIT: I've found two solutions for this now...

Method 1. get rid of crap you probably don't need:

As I found in this Stack Overflow question, basically nearly everything I had added in my listing of "things I've tried" above were unnecessary. Steps to fix:

  1. Remove everything I've listed that I've tried above. That means no custom headers specified at all in the Web.Config or elsewhere like the Global.asax, no custom jquery settings, etc.

  2. .. except for RouteTable.Routes.MapHubs(new HubConfiguration { EnableCrossDomain = true }); In the Application_Start.

  3. Also you still need to set the $.connection.hub.url = 'http://localhost:13370/signalr/hubs';

... that's it. this is probably the best solution and the one I ended up using.

Method 2. use jsonp if you're still having problems in Chrome:

If you're still having problems like this in Chrome you can use jsonp to get that negotiate script to download properly... adding the following to my JavaScript hub start solved the issue:

//detect chrome
var isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;

//set the connection url.
$.connection.hub.url = 'http://localhost:13370/signalr/hubs';

//use jsonp if chrome
$.connection.hub.start({
    jsonp: isChrome
});

There is probably a better way to do this that tests the browser capabilities and sets jsonp accordingly... looking at the user agent feels dirty as hell... but this solved my problem in the interim. I hope this helps someone else.

like image 166
Ben Lesh Avatar answered Oct 20 '22 14:10

Ben Lesh


This worked for me. Put this method on Global.asax.cs

protected void Application_BeginRequest(object sender, EventArgs e)
{
    Context.Response.AppendHeader("Access-Control-Allow-Credentials", "true");
    var referrer = Request.UrlReferrer;
    if (Context.Request.Path.Contains("signalr/") && referrer != null)
    {
        Context.Response.AppendHeader("Access-Control-Allow-Origin", referrer.Scheme + "://" + referrer.Authority);
    }
}
like image 44
Akira Yamamoto Avatar answered Oct 20 '22 13:10

Akira Yamamoto