【问题标题】:Cross-Origin Request Blocked Reason: CORS preflight channel did not succeed跨域请求被阻止原因:CORS 预检通道未成功
【发布时间】:2015-08-12 04:12:46
【问题描述】:

我创建了一个 phonegap 应用程序,我在其中调用驻留在 nopCommerce 插件中的 WCF 服务。

发送 api 请求时出现以下错误:

跨域请求被阻止:同源策略不允许读取位于http://testwebsite.com/Plugins/NopRestApi/RemoteService/WebService.svc/GetData 的远程资源。 (原因:CORS 预检通道未成功)。

跨域请求被阻止:同源策略不允许读取位于http://testwebsite.com/Plugins/NopRestApi/RemoteService/WebService.svc/GetData 的远程资源。 (原因:CORS 请求失败)。

使用 Ajax 的 API 调用

$.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);                
  }
});

通过对 google 的一些研究,我在我的 Web.config 文件中添加了以下内容。

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

我已经尝试了很多方法,甚至通过关注How to temporarily disable XSS protection in modern browsers for testing? 链接禁用了浏览器跨源请求检查,但同样的问题仍然存在。

有没有人遇到过类似的问题并解决了?

谢谢!

【问题讨论】:

  • 我有类似的经历,浏览器带有预检功能,Cors 无法正常工作。没有预检的浏览器,Cors 可以工作!
  • @KennethLi 谢谢。你说的是哪个浏览器?还有一件事,它可以在 Android、iOS 等的 phonegap 中工作?
  • 我已经解决了这个问题,它现在适用于所有已知的 PC 浏览器、所有已知的移动浏览器、所有版本的 android 以及所有版本的 iPhone 和 iPad。问题是,我忘记了我是怎么做到的,现在在我的代码中寻找它。
  • 所有已知的意思是 IE、safari、chrome、firefox
  • 我知道了,这是预检期间的 OPTIONS 调用,因此我在 global.asax 中为所有 OPTIONS 调用添加了默认响应。然后 cors 在所有浏览器而不是某些浏览器中工作。顺便说一句,我不知道如何在评论中添加代码,所以我将其添加到答案中,请看一下。

标签: wcf cross-domain phonegap-plugins nopcommerce


【解决方案1】:

在您的Global.asax 中,添加以下代码:

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();
     }
 }

应该可以的

【讨论】:

    【解决方案2】:

    您需要允许来自 WCF 服务的跨域请求。

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

    在你的函数中添加这个,但在你的数据从函数返回之前添加这个。

    How to implement “Access-Control-Allow-Origin” header in asp.net 可能会有所帮助。

    【讨论】:

    • 感谢您的回复。实际上我已经添加了,但问题是即使从 about:config 禁用跨域/源设置后,我也无法从浏览器发出 api 请求。我想现在它不再支持了。但是主要的想法是我可以通过在 phonegap 应用程序配置文件中启用 &lt;allow origin="*" /&gt; 从 phonegap 应用程序访问。
    • 在 phonegap 应用配置文件中启用 这个“phonegap 应用”有效吗?如果是,则以完全解决方案回复..
    【解决方案3】:

    在 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
    

    web.config show 中的 allow 方法也添加了 OPTIONS。

    <?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>
    

    很抱歉 global.asax 在 VB 中,因为我是 VB 人,我想你可以将它转换为 C#。

    根据您的要求,更新如下:

    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);
            }
        });
    }
    

    下面是我用VB写的web服务(clsSQL是一个用VB写的Class,包含了我所有后端业务逻辑的功能,可以访问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
    

    下面是我如何定义参数的数据类型:

    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
    

    【讨论】:

    • 是的,我可以把它转换成c#。我需要测试一下!
    • 在 BeginRequest 中添加这 3 行之前,CORS 在一些没有预检的浏览器中工作,但在其他一些有预检的浏览器中失败,但我忘记了哪个是哪个。添加这 3 行后,CORS 可以在我安装的所有浏览器中运行。 (当然,我没有测试所有版本的浏览器,但我安装的是最新的)
    • 我已经添加了这个,但仍然有同样的问题。你能发布你的 Ajax 调用,用于 api 调用 POST 类型以及你使用的 jQuery 版本吗??
    • 我是用手机回复的,电脑没带,但我记得jquery是2.2.0
    • 顺便说一句:async = false 简直要了我的命!当连接速度很慢时,我的应用程序。就挂在那里!现在我需要花几天时间将所有同步更改为异步!你有类似的问题吗?
    猜你喜欢
    • 1970-01-01
    • 2016-03-15
    • 2020-08-16
    • 1970-01-01
    • 2016-12-21
    • 2016-04-02
    • 1970-01-01
    • 2021-11-29
    • 2021-10-03
    相关资源
    最近更新 更多