19

对这个问题发疯。我有一个包含 2 个项目的解决方案,其中一个是带有 jquery ajax 调用的普通旧 html,而另一个是 WCF 服务。html 页面将向 WCF 服务发出 ajax 调用以获取 json 字符串并将其用于显示目的。

现在的问题是,每当我在调试模式下运行时,html 页面和 WCF 都将以不同的端口启动。这在我执行测试时为我创建了一个跨域问题(即在 Firefox 中调用 type = OPTIONS 时出现 405 Method Not Allowed 错误)。我会三重检查我的 ajax 脚本上的调用方法,并且 WCF 服务是相同的(GET)。

我会搜索谷歌,但发现要么我必须安装扩展程序,要么在 IIS 上执行一些配置,我发现这很麻烦,因为我正在做的事情很简单。按照一个示例,我将在 web.config 中添加以下配置,但它不起作用:

    <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="crossDomain" crossDomainScriptAccessEnabled="true" />
      </webHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="MobileService.webHttpBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="MyServiceBehavior">
          <serviceMetadata httpGetEnabled="true"  />
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    <services>
      <service name="MobileService.SimpleMemberInfo" behaviorConfiguration="MyServiceBehavior">
        <endpoint address="" binding="webHttpBinding" contract="MobileService.IMemberInfo" bindingConfiguration="crossDomain" behaviorConfiguration="MobileService.webHttpBehavior">
        </endpoint>
      </service>
    </services>
  </system.serviceModel>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Methods" value="GET" />
        <add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
      </customHeaders>
    </httpProtocol>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
    </system.webServer>

任何人有任何想法摆脱这个烦人的问题?

编辑:补充一点,我正在使用与 VS Studio 2012 一起提供的 IIS Express 运行调试

添加 WCF 代码并更新 web.config

[ServiceContract]
public interface IMemberInfo
{
    [WebInvoke(Method = "GET",
           BodyStyle = WebMessageBodyStyle.Wrapped,
           ResponseFormat = WebMessageFormat.Json
    )]
    [OperationContract]
    string GetMemberInfoById();
    // TODO: Add your service operations here
}

我的脚本:

$(document).ready(function () {
    $.ajax("http://localhost:32972/SimpleMemberInfo.svc/GetMemberInfoById", {
        cache: false,
        beforeSend: function (xhr) {
            $.mobile.showPageLoadingMsg();
        },
        complete: function () {
            $.mobile.hidePageLoadingMsg();
        },
        contentType: 'application/json',
        dataType: 'json',
        type: 'GET',
        error: function () {
            alert('Something awful happened');
        },
        success: function (data) {
            var s = "";

            s += "<li>" + data + "</li>";
            $("#myList").html(s);

        }
    });
});
4

5 回答 5

11

您需要使用 JSONP 进行跨域调用以绕过浏览器限制,并将您的 web.config 更新为crossDomainScriptAccessEnabled设置为 true 以绕过服务器限制。这里的答案中有一个很好的例子:how to Avoid cross domain policy in jquery ajax for sumption wcf service?

您可能还会遇到 GET 请求问题。尝试此处列出的修复: 使 WCF Web 服务与 GET 请求一起工作

总而言之,您需要一个看起来像这样的 web.config:

<bindings>
  <webHttpBinding>
    <binding name="crossDomain" crossDomainScriptAccessEnabled="true" />
  </webHttpBinding>
</bindings>
<behaviors>
  <endpointBehavior>
    <behavior name="restBehavior">
      <webHttp />
    </behavior>
  </endpointBehavior>
  <serviceBehavior>         
     <behavior name="MyServiceBehavior">
        <serviceMetadata httpGetEnabled="true"  />
        <serviceDebug includeExceptionDetailInFaults="true"/>
     </behavior>
  </serviceBehavior>
</behaviors>
<services>
  <service name="..." behaviorConfiguration="MyServiceBehavior">
    <endpoint address="" binding="webHttpBinding" bindingConfiguration="crossDomain" 
              contract="..." behaviorConfigurations="restBehavior" /> 
  </service>
</services>

(请注意,服务和端点都附加了行为,分别允许 webHttp 调用和 httpGet 调用,并且绑定显式启用了跨域访问)。

...这样装饰的服务方法:

[ServiceContract]
public interface IMyService
{
    [WebGet] // Required Attribute to allow GET
    [OperationContract]
    string MyMethod(string MyParam);
}

...以及使用 JSONP 的客户端调用:

<script type="text/javascript">
$(document).ready(function() {
    var url =  "...";
    $.getJSON(url + "?callback=?", null, function(result) { // Note crucial ?callback=?
       // Process result
    });
});
</script>
于 2012-11-05T09:39:20.837 回答
8

然而,它是一个旧线程,但我想添加我对我面临的问题以及我为 CORS 工作所获得的解决方案的评论。我正在以下环境中开发 Web 服务:

  1. WCF 网络服务。
  2. .NET 3.5 框架。
  3. 在现有的 asp.net 网站中添加了 wcf 网络服务。
  4. 视觉工作室 2008

大多数人提到在 web.configcrossDomainScriptAccessEnabled下的标签中添加属性。<webHttpBinding>我不确定这是否有效,但它在 3.5 版本中不可用,所以我别无选择。我还发现在 web.config 中添加以下标签会起作用......

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

但没有运气...不断收到 405 方法不允许的错误

在与这些选项进行了很多努力之后,我找到了另一种解决方案,可以根据下面给出的动态将这些标头添加到 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("Cache-Control", "no-cache");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization");
        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
        HttpContext.Current.Response.End();
    }
}

并从 web.config 中删除。发布网站并继续到客户端 jquery/ajax...您将从 api 调用中获取数据。祝你好运!

于 2014-02-21T10:25:36.920 回答
3

对我有用的是启用 IIS 的 WCF 相关功能: 在此处输入图像描述

于 2021-02-02T14:45:10.217 回答
2

只是想在底部附加一些与 CORS 返工有关的问题 - 它的问题是,如果您的输入不支持 GET 和 POST 方法,则 OPTIONS 请求实际上并没有返回正确的允许标头。它实际上并没有查看 WCF 端点上实际允许哪些方法 - 它只是在客户端执行 OPTIONS 请求时人为地说“GET,POST”允许应用程序中的每个端点(这实际上是客户端询问什么)支持)。

这可能没问题,如果你不是真的依赖 OPTIONS 方法中的信息来返回一个有效的方法列表(就像一些 CORS 请求的情况一样) - 但如果你是,你需要做类似的事情这个问题的解决方案: How to handle Ajax JQUERY POST request with WCF self-host

基本上,每个端点都应该实现:

Webinvoke(Method="OPTIONS", UriTemplate="")

并调用一个适当的方法,该方法将适当的标头加载到调用者的响应中(包括该端点的适当的“访问控制允许方法”列表)。托管的 WCF 端点不会自动为我们执行此操作,这有点糟糕,但这是一种允许更好地控制端点的解决方法。在该解决方案中,在端点实现中加载了正确的响应标头:

public void GetOptions()
    {
        // The data loaded in these headers should match whatever it is you support on the endpoint
        // for your application. 
        // For Origin: The "*" should really be a list of valid cross site domains for better security
        // For Methods: The list should be the list of support methods for the endpoint
        // For Allowed Headers: The list should be the supported header for your application

        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization");
    }
于 2014-03-17T16:48:35.997 回答
-2

尝试使用。 WebInvoke(Method = "POST") 代替WebInvoke(Method = "GET")

于 2015-12-22T13:12:11.510 回答