Cross-Origin Request Blocked Reason: CORS preflight channel did not succeed
Asked Answered
W

3

6

I've created one phonegap app where I'm calling WCF service which resides in nopCommerce plugin.

I'm getting following error while sending api request:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://testwebsite.com/Plugins/NopRestApi/RemoteService/WebService.svc/GetData. (Reason: CORS preflight channel did not succeed).

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://testwebsite.com/Plugins/NopRestApi/RemoteService/WebService.svc/GetData. (Reason: CORS request failed).

API call using Ajax

$.ajax({
  crossDomain: true,
  type: "POST",
  contentType: "application/json",
  async: false,
  url: "http://testwebsite.com/Plugins/NopRestApi/RemoteService/WebService.svc/GetData",
  data: "{storeId:" + storeId + ", languageId:" + languageId + ", customerId:" + customerId + "}",            
  //data: { storeId: storeId, languageId: languageId, customerId: customerId },
  dataType: 'json',
  //jsonp: false,
  success: function (data) {
      alert(data.d);                
  },
  error: function (xhr, textStatus, error) {
      alert("Error! " + error);                
  }
});

I've added following in my Web.config file by some research on google.

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

I've tried many ways even disabled browser cross origin request check by following How to temporarily disable XSS protection in modern browsers for testing? link but still same issue persist.

Does anyone have similar issue and resolved?

Thanks!

Wilterdink answered 29/5, 2015 at 10:21 Comment(6)
I got similar experience, browser with preflight, Cors not working. browser without preflight, Cors works!Jardena
@KennethLi thanks. Which browser, are you talking about? One more thing, It'll work in phonegap for Android, iOS etc?Wilterdink
I already solved the problem and it now works in all known pc browsers, all known mobile browsers, all version of android and all version of iPhone and iPad. The problem is, I forgot how I did it, looking for it in my codes now.Jardena
All known means IE, safari, chrome, firefoxJardena
I got it, it's a OPTIONS call during a preflight, so I add a default response in the global.asax for all OPTIONS call. Then the cors works in ALL browsers instead of some browsers. By the way I don't know how to add codes in comment so I add it in answer, pls take a look.Jardena
OK, is there no other way to do so?Wilterdink
J
4

In global.asax:

Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
    ' Fires at the beginning of each request
    If Request.HttpMethod = "OPTIONS" Then
        Response.Flush()
    End If

End Sub

And the allow method in web.config show add OPTIONS too.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="aspnet:MaxJsonDeserializerMembers" value="1000000" />
  </appSettings>

  <connectionStrings/>
  <system.web>
    <compilation debug="true" strict="false" explicit="true" targetFramework="4.5.1"/>
    <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID">
      <namespaces>
        <clear/>
        <add namespace="System"/>
        <add namespace="System.Collections"/>
        <add namespace="System.Collections.Specialized"/>
        <add namespace="System.Configuration"/>
        <add namespace="System.Text"/>
        <add namespace="System.Text.RegularExpressions"/>
        <add namespace="System.Web"/>
        <add namespace="System.Web.Caching"/>
        <add namespace="System.Web.SessionState"/>
        <add namespace="System.Web.Security"/>
        <add namespace="System.Web.Profile"/>
        <add namespace="System.Web.UI"/>
        <add namespace="System.Web.UI.WebControls"/>
        <add namespace="System.Web.UI.WebControls.WebParts"/>
        <add namespace="System.Web.UI.HtmlControls"/>
      </namespaces>
    </pages>
    <authentication mode="Windows"/>
    <webServices>
      <protocols>
        <add name="HttpGet"/>
        <add name="HttpPost"/>
      </protocols>
    </webServices>
  </system.web>
  <system.webServer>
    <staticContent>
      <mimeMap fileExtension=".apk" mimeType="application/octet-stream"/>
    </staticContent>
  <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
      <remove name="OPTIONSVerbHandler"/>
      <remove name="TRACEVerbHandler"/>
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/>
    </handlers>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Methods" value="POST,OPTIONS,GET"/>
        <add name="Access-Control-Allow-Headers" value="Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, Accept"/>
        <add name="Access-Control-Allow-Origin" value="*"/>
      </customHeaders>
    </httpProtocol>
  </system.webServer>
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <assemblyIdentity name="System.Web.Cors" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
                <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0"/>
            </dependentAssembly>
        </assemblyBinding>
    </runtime>
  <system.web.extensions>
    <scripting>
      <webServices>
        <jsonSerialization maxJsonLength="4000000" />
      </webServices>
    </scripting>
  </system.web.extensions>

</configuration>

Sorry that the global.asax is in VB cuz I'm a VB guy, I think you can convert it to C#.

Per your request, update as follow:

function funCheckWS() {
    var tblLogin = {};
    tblLogin.strLoginName = "UserName";
    tblLogin.strPassword = "123456";
    jQuery.support.cors = true;
    $.ajax({
        type: 'POST',
        url: 'http://www.example.com/wsMain.asmx/funCheckWS',
        data: "{tblLogin:" + JSON.stringify(tblLogin) + "}",
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        crossDomain: true,
        // async: false,
        async: true,
        success: function (r) {
            // Browser support WS
            gloBolWS = true;
            // alert("funCheck: " + r.d.strPassword);
        },
        error: function (xhr, ajaxOptions, thrownError) {
            // Browser does not support WS
            //alert(xhr.status);
            //alert(thrownError);
        }
    });
}

Below is my web services in VB (the clsSQL is a Class written in VB that contains functions of all my backend business logics and can access the sql server):

Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.ComponentModel
Imports System.Web.Script.Serialization
Imports System.Web.Script.Services
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Web

<System.Web.Script.Services.ScriptService()> _
<System.Web.Services.WebService(Namespace:="http://tempuri.org/")> _
<System.Web.Services.WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<ToolboxItem(False)> _
Public Class wsMain
    Inherits System.Web.Services.WebService

    Private clsSQL As New wxdlSQL.clsSQL()

    Private tblLogin As tabLogin
    <WebMethod()> _
    <ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
    Public Function funCheckWS(tblLogin As tabLogin) As tabLogin
        tblLogin.strLoginName += "Hello World"
        Return tblLogin
    End Function
End Class

Below is how I define data type for the parameters:

Public Class tabLogin
    Private _loginname As String
    Public Property strLoginName As String
        Get
            Return _loginname
        End Get
        Set(ByVal value As String)
            _loginname = value
        End Set
    End Property
    Private _password As String
    Public Property strPassword As String
        Get
            Return _password
        End Get
        Set(ByVal value As String)
            _password = value
        End Set
    End Property
End Class
Jardena answered 29/5, 2015 at 15:51 Comment(6)
Yeah, I can convert it into c#. I need to test it!Wilterdink
Before these 3 lines in BeginRequest were added, the CORS works in some browsers without preflight but failed in some other browsers with preflight but I forgot which is which. After these 3 lines are added, CORS works in all browsers I've installed. (Of course, I didn't test all versions of those browsers, but I installed the latest)Jardena
I've added this but still having same issue. Can you post your Ajax call for api call POST type and which version of jQuery you'd used??Wilterdink
I'm using mobile phone to reply, don't have the pc with me, but I remember the jquery is 2.2.0Jardena
by the way: the async = false just killing me! when the connection is slow, my app. just hangs there! now I need to spend days to change all my sync to async! do you have similar problem?Jardena
Thanks. My issue only was I was not able to access that directly from web browsers even after disabling origin settings. However main think is I can access from phonegap app by enabling <allow origin="*" /> in app's config file. No need to add settings in global.asax file, only you need to add allow origin settings in Web.config file as you are currently using. For ajax call, no need to send crossDomain as well as asyc parameters while posting data to server. Make sure you are sending JSON as request otherwise it'll take longer response time.Wilterdink
C
3

You need to allow cross domain request from your WCF service.

Response.AppendHeader("Access-Control-Allow-Origin", "*");

add this in your function but add this before your data return from function.

How to implement “Access-Control-Allow-Origin” header in asp.net might be helpful.

Cap answered 1/6, 2015 at 12:53 Comment(2)
Thanks for the reply. Actually I already added that but the thing is I'm not able to make api request from browsers even after disable cross-domain/origin setting from about:config. I think now it's no longer supported. However main think is I can access from phonegap app by enabling <allow origin="*" /> in phonegap app config file.Wilterdink
Is this " phonegap app by enabling <allow origin="*" /> in phonegap app config file " works? if yes then reply with exctly solution..Cap
F
1

In your Global.asax, add the following code:

protected void Application_AuthenticateRequest(object sender, EventArgs e){
    Response.AddHeader("Access-Control-Allow-Origin", "*");
    if (Context.Request.HttpMethod.Equals("OPTIONS")){
        Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
        Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        Response.StatusCode = (int)System.Net.HttpStatusCode.OK;
        Context.ApplicationInstance.CompleteRequest();
     }
 }

That should work

Flournoy answered 5/8, 2015 at 13:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.