Ajax Web Service Call - No 'Access-Control-Allow-Origin' header is present

18,954

Solution 1

I will prefer to just enable CORS than changing all your AJAX call.

Do you try to modified the web.config for the webservice to add the following line yet ?

<system.webServer>
    <httpProtocol>
        <customHeaders>

            <add name="Access-Control-Allow-Origin" value="*" />
        </customHeaders>
    </httpProtocol>

Check also this questions for if CORS / JSONP is better for you So, JSONP or CORS?

Solution 2

The key to solving CORS errors is paying attention to the headers in the server response(s). You need to download an http traffic monitor like Fiddler to examine these headers. Then, you can use it in conjunction with the browser console errors to figure out exactly what's going wrong.

Here's what a typical/successful 200 OK CORS response looks like (taken directly from Fiddler):

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Vary: Accept-Encoding
Server: Microsoft-IIS/7.5
Access-Control-Allow-Origin: http://localhost:1234
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET,POST,OPTIONS
X-AspNet-Version: 4.0.30319
X-UA-Compatible: IE=edge
Persistent-Auth: false
WWW-Authenticate: Negotiate oYG2MIGzoAMKAQChCwYJKoZIgvcSAQIC...etc.
Date: Fri, 08 May 2015 01:14:37 GMT
Connection: close
Content-Length: 4711

...response body etc. etc. 

In the case where you're getting the No 'Access-Control-Allow-Origin' header is present on the requested resource, the header is either missing from the response or being delivered in a way that violates Chrome's implementation of the W3C spec.

By looking at your web.config file, I'm willing to bet its the latter. For example, this is a valid Access Control Allow Origin header with multiple entries:

Access-Control-Allow-Origin: http://domain1.com,http://domain2.com

whereas the way your web.config headers section is configured will deliver multiple entries, which is generally invalid

Access-Control-Allow-Origin: http://localhost:17256
Access-Control-Allow-Origin: *

... especially in scenarios where authentication and the Access-Control-Allow-Credentials headers are being passed to secured endpoints:

Share:
18,954
Admin
Author by

Admin

Updated on July 26, 2022

Comments

  • Admin
    Admin almost 2 years

    Heyya,

    I know this question has been asked before and I have read each and every answer of every single question here but still can't seem to get my project working properly. My scenario is a bit different than other questions though, not sure if this makes any difference but here we go.

    I have a project made of web services. Services alone works fine, there is no problem with that. And there is this another project which handles the UI part of things and call these services through jquery ajax. It has been working fine because I haven't tested this case on Google Chrome before. Everything works perfectly on Internet Explorer.

    Now; my web service application runs on port 40000 (localhost:40000) and the UI project runs on some other random port but still in the localhost. Like I said, my ajax calls etc works perfectly on Internet explorer but when it comes to Google Chrome it fails. The console shows the following error:

    XMLHttpRequest cannot load http://127.0.0.1:40000/abc.asmx/TheMethodName. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:17256' is therefore not allowed access. The response had HTTP status code 400.
    

    By the way, it was like "localhost:40000" before so some post on the internet suggested that I should change it to an IP address instead of localhost.

    Anyway, I have also edited my web.config file on my web service project and added the following (which doesn't make any sense)

    <system.serviceModel>
      <bindings>
        <webHttpBinding>
          <binding name="crossDomain" crossDomainScriptAccessEnabled="true">
          </binding>
        </webHttpBinding>
      </bindings>
    
      <behaviors>
    
        <serviceBehaviors>
          <behavior>
            <serviceMetadata httpGetEnabled="true" />
            <serviceDebug includeExceptionDetailInFaults="false" />
          </behavior>
        </serviceBehaviors>
    
      </behaviors>
    
      <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    </system.serviceModel>
    
    
    <system.webServer>
      <modules runAllManagedModulesForAllRequests="true" />
      <httpProtocol>
        <customHeaders>
          <add name="Access-Control-Allow-Origin" value="http://localhost:17256" />
          <add name="Access-Control-Allow-Origin" value="*" />
          <add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS" />
          <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
          <add name="Access-Control-Max-Age" value="1728000" />
    
        </customHeaders>
      </httpProtocol>
    </system.webServer>
    

    BTW, if I use the first line: it completely fails and says the response header messages do not match and I can't even start the service invoke.

    And yes, I have also edited my ajax call, added the following parameter:

    crossDomain: true,
    

    Now, what am I missing here? I have been on this for days now and I am about to lose my mind :) It is kinda too late to change the whole structure of the project (service - UI style I mean) since loads of code have been written to the services and UI projects. Please help I'm desperate! :)

    Cheers


    Edit:

    So it turns out I need to use JSONP, not JSON - since it doesn't get stuck with Access Control thing, which is fine. I can convert my ajax calls into JSONP ones. But I need another help :)

    I have written a global ajax method that is called from each operation on seperate pages and it works like charm (on Internet Explorer again of course). Now what should I do to convert this wrapper function into a jsonp thingy?

    function RemoteCall(WebService, RemoteMethod, RemoteParameters, callbackResult) {
    
    if (RemoteParameters == null || RemoteParameters == "") {
        RemoteParameters = "{ }";
    }
    
    var remoteCall = $.ajax({
        type: "POST",
        url: ProvideService(WebService, RemoteMethod),
        data: RemoteParameters,
        contentType: ajaxContentType,
        dataType: ajaxDataType,
        async: true,
        crossDomain: true,
        success: function (msg) {
            msg.header("Access-Control-Allow-Origin", "*");
            callbackResult(msg.d);
        },
        error: function (xhr, ajaxOptions, thrownError) {
            callbackResult(xhr.status + '\r\n' + thrownError + '\r\n' + xhr.responseText);
        }
    });
    

    }

    I saw some posts that I should add a property as jsonp: 'jsonp_callback' with the callback method (this is where I am confused). What about this?

    Another thing; I have been sending my json parameters as a text in a variable like

    var jSONParams = '{ UserID: "1", EmailAddress: "[email protected]" }'; 
    

    Should I keep sending this as the same format or should it be converted to some sort of JSON object or something?

    BTW: my global ajax function is in a completely seperate JS file - not sure if it makes any difference though...

    Cheers