【问题标题】:enable CORS using WCF使用 WCF 启用 CORS
【发布时间】:2020-01-29 17:28:54
【问题描述】:

我正在尝试使用 WCF 启用 CORS。 但是我得到 Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource。因此,Origin 'http://localhost' 不允许访问。响应的 HTTP 状态代码为 404。

这是我的 Global.asax

  protected void Application_BeginRequest(object sender, EventArgs e)
    {

        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        {
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
            HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
            HttpContext.Current.Response.End();
        }
    }

这是我的 web.config

    <configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
    <system.serviceModel>
	<bindings>
      <webHttpBinding>
        <binding name="TransportSecurity">
          <security mode="Transport">
            <transport clientCredentialType="None"/>
          </security>
        </binding>
      </webHttpBinding>
    </bindings>
      <behaviors>
        <endpointBehaviors>
          <behavior name="RESTAPI03.testAspNetAjaxBehavior">
            <webHttp />
          </behavior>
        </endpointBehaviors>
        <serviceBehaviors>
          <behavior name="RESTAPI03.testAspNetAjaxBehavior">
            <serviceMetadata httpGetEnabled="true" />
            <serviceDebug includeExceptionDetailInFaults="true" />
          </behavior>
        </serviceBehaviors>
      </behaviors>
      <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
      <services>
        <service name="RESTAPI03.test">
          <endpoint address="" behaviorConfiguration="RESTAPI03.testAspNetAjaxBehavior"
              binding="webHttpBinding" bindingConfiguration="TransportSecurity" contract="RESTAPI03.Hotels" />
        </service>        
      </services>
	  <standardEndpoints>
    <webScriptEndpoint>
      <standardEndpoint crossDomainScriptAccessEnabled="true"></standardEndpoint>
    </webScriptEndpoint>
  </standardEndpoints>
    </system.serviceModel>
    <system.webServer>
      <httpProtocol>
        <customHeaders>
          <add name="Access-Control-Allow-Origin" value="*"/>
          <add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
          <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS" />
          <add name="Access-Control-Max-Age" value="1728000" />
        </customHeaders>
      </httpProtocol>
    </system.webServer>
  </configuration>

这是我的应用程序项目中的代码

const httpOptions = {
         headers: new HttpHeaders({
         'Access-Control-Allow-Origin' : '*'
        })
    }

    return this.httpClient.get('https://www.example/1'  httpOptions ).subscribe(data => {
         console.log("s");
         console.log(JSON.stringify(data));
      }, err => {
         console.log("err => ");
         console.log( JSON.stringify(err));
      });

但仍然无法正常工作。我错过了什么?

【问题讨论】:

  • 尝试在您的客户端代码中添加 Content-Type 和 Accept 标头。另外,您是否正在发送带有凭据的请求?因为在这种情况下,Access-Control-Allow-Origin 设置为 '*' 会引发错误
  • 如何发送带凭证的请求?我把这样的凭证弄错了。 const httpOptions = {headers: new HttpHeaders({ 'Content-Type':'application/json','Accept':'application/json','Access-Control-Allow-Origin' : '*'}), withCredentials:'true'}
  • withCredentials:'true' 表示您正在发送 cookie、身份验证等凭据。在这种情况下,您的服务器不应将 Acces-Control-Allow-Origin 设置为“*”。它应该只允许一个域。稍后我会发布详细的答案和绕过 CORS 限制的方法。

标签: wcf ionic-framework


【解决方案1】:

Web 应用程序在执行跨域 HTTP 请求时 请求具有不同来源(域、协议或 端口)从它自己的。

CORS(跨源资源共享)是网络浏览器实现 SOP(同源策略)的一种方式,它表示只允许同源访问服务器的资源。

解决方法:使用原生 http 插件。因为 CORS 和 SOP 策略仅由浏览器强制执行,因此您不会在其他 http 客户端(如本地 http 调用和 POSTman)上收到 CORS 错误。 https://ionicframework.com/docs/native/http

为什么会这样:

  • 假设登录表单由 www.example.com/login 返回。现在,来源变成了 www.example.com
  • 当您单击提交时,浏览器不会立即请求服务器。它将首先通过发送预检 OPTIONS 请求来验证服务器是否正在接受来自该来源的请求(由于浏览器遵循的 SOP 策略)。
  • 如果服务器允许来自此源的请求,则服务器将发送一些 CORS 标头,包括 ACCESS-CONTROL-ALLOW-ORIGIN 标头。

阅读更多:https://ionicframework.com/docs/faq/cors

  • 如果服务器说是(通过发送有效的 CORS 标头),浏览器将提交表单,其中 Origin 标头 设置为“www.example.com”以及登录参数。
  • 在其他情况下,您可能在 www.example.com/api/login 服务器上有一个登录 API,并且您从不同的来源发送 POST 请求,http://localhost 对于 IONIC 应用程序
  • 由于来源不同,您需要在服务器上设置 CORS 标头,以便允许来自http://localhost 的任何请求。但是有一些因素需要记住。就像,当您发送带有凭据的请求时,将 ACCESS-CONTROL-ALLOW-ORIGIN 设置为 '*' 不起作用。

我建议您阅读有关 CORS 及其政策的文档。它将在将来对您有所帮助。 https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

【讨论】:

    【解决方案2】:

    起初,我怀疑您用于创建 Restful 样式 WCF 服务的配置有问题。
    注意服务部分的name 属性和端点部分的contract 属性。

    <service name="RESTAPI03.test">
              <endpoint address="" behaviorConfiguration="RESTAPI03.testAspNetAjaxBehavior"
                  binding="webHttpBinding" bindingConfiguration="TransportSecurity" contract="RESTAPI03.Hotels" />
            </service> 
    

    服务的name 属性应该是服务实现类的限定名称,contract 属性应该是服务契约的限定名称,如下所示。

    <service name="WcfService3.Service1" behaviorConfiguration="mybehavior">
        <endpoint address="" binding="webHttpBinding" bindingConfiguration="mybinding" contract="WcfService3.IService1" behaviorConfiguration="rest"/>
      </service>
    

    请参考我的ProtocolMapping 功能配置。它适用于HTTP 和HTTPS 协议,并且无论任何服务合同如何都支持您的服务。

     <system.serviceModel>
        <bindings>
          <webHttpBinding>
            <binding name="httpsbinding">
              <security mode="Transport">
                <transport clientCredentialType="None"></transport>
              </security>
            </binding>
          </webHttpBinding>
        </bindings>
        <behaviors>
          <serviceBehaviors>
            <behavior>
              <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
              <serviceDebug includeExceptionDetailInFaults="true" />
            </behavior>
          </serviceBehaviors>
          <endpointBehaviors>
            <behavior>
              <webHttp />
            </behavior>
          </endpointBehaviors>
        </behaviors>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
        <protocolMapping>
          <add binding="webHttpBinding" scheme="http"></add>
          <add binding="webHttpBinding" scheme="https" bindingConfiguration="httpsbinding"/>
        </protocolMapping>
      </system.serviceModel>
    

    其次,在Restful WCF服务中开启CORS通常有两种方式。
    1.在WCF项目中添加global.asax文件,代码如下 sn-ps 到Application_BeginRequest 事件。

    protected void Application_BeginRequest(object sender, EventArgs e)
            {
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
                if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
                {
                    HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
                    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
                    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With,Accept");
                    HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
                    HttpContext.Current.Response.End();
                }
            }
    
    1. 添加global.asax 文件并修改Application_BeginRequest 事件。
    if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
                    {
                        Response.End();
                    }
    

    随后,将以下配置添加到 Web.config 文件中。

       <httpProtocol>
          <customHeaders>
            <add name="Access-Control-Allow-Origin" value="*"/>
            <add name="Access-Control-Allow-Headers" value="content-type" />
            <add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
          </customHeaders>
        </httpProtocol>
      </system.webServer>
    

    如果问题仍然存在,请随时告诉我。

    【讨论】:

      猜你喜欢
      • 2014-03-03
      • 2015-01-02
      • 2015-11-26
      • 1970-01-01
      • 2019-08-17
      • 2019-04-09
      • 1970-01-01
      • 2015-02-19
      • 1970-01-01
      相关资源
      最近更新 更多