WCF错误:405方法不允许。

23

这个问题让我十分困扰。我的解决方案包含两个项目,一个是普通的HTML页面,使用jQuery的ajax调用;而另一个则是WCF服务。HTML页面会向WCF服务发起ajax调用以获取JSON字符串并用于显示。

现在的问题在于,每当我以调试模式运行时,HTML页面和WCF服务将在不同的端口上启动。这导致了跨域问题,当我进行测试时(例如在Firefox中收到“405方法不允许”的错误),这就成为了一个问题。我已经反复检查了我的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);

        }
    });
});

这个链接可能会有所帮助:http://stackoverflow.com/questions/2202500/wcf-service-405-method-not-allowed-exception - Mihai
谢谢。我尝试了,但它没成功。 - ipohfly
操作没问题...但如果没有任何答案真正有帮助,那我应该选择最接近的答案吗? - ipohfly
我已经编辑了你的标题。请参考“问题的标题应该包含“标签”吗?”,在那里达成共识是“不应该”。 - John Saunders
5个回答

11

为了绕过浏览器的限制并进行跨域调用,您需要使用JSONP,并将您的web.config更新为crossDomainScriptAccessEnabled设置为true以绕过服务器限制。这里有一个很好的示例答案:如何避免使用jquery ajax消费wcf服务中的跨域策略?

您还可能遇到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>

谢谢。我刚试了一下,但是没有成功,客户端示例的链接已经失效了。我尝试在我的web.config中添加crossDomain绑定,但是也没有成功。 - ipohfly
只需在Google或此处搜索JSONP - 有大量示例,例如:https://dev59.com/rnE85IYBdhLWcg3wpFEa 只修复服务器端是行不通的。 - Jude Fisher
另外,你能展示一下你的WCF代码吗?除了像上面的例子那样在Web.Config中允许WebGet之外,你还需要使用正确的属性修饰你的WCF方法。 - Jude Fisher
非常感谢您的帮助。我尝试了新的设置,但仍然不起作用,但我还没有尝试过JSON方法。我也更新了我的代码部分。 - ipohfly
终于!在使用JSONP(回调参数非常关键)后,它成功了!!!万分感谢! - ipohfly

8
尽管这是一个旧主题,但我想补充我的评论,介绍我所遇到的问题以及CORS工作的解决方案。 我在以下环境中开发Web服务:
  1. WCF Web服务
  2. .NET 3.5框架
  3. 将WCF Web服务添加到现有的ASP.NET网站中
  4. Visual Studio 2008
大多数人提到在web.config中在标记下添加crossDomainScriptAccessEnabled属性。我不确定这是否有效,但它在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中删除<system.web.extensions>。发布网站并继续客户端jquery/ajax...然后您将从api调用中获取数据。祝好运!


7

我做的是启用IIS的WCF相关功能:enter image description here


2
只是想在 CORS 重构的底部附加一些问题 - 它的问题在于,如果您的输入不支持 GET 和 POST 方法,则 OPTIONS 请求实际上不会返回正确的允许标头。它实际上并没有查看 WCF 终结点上实际允许的方法 - 当客户端执行 OPTIONS 请求(这实际上是客户端询问支持什么)时,它只是人为地说“GET、POST”对于应用程序中的每个终结点都是允许的。
如果你不真正依赖 OPTIONS 方法中的信息来返回一个有效的方法列表(就像某些 CORS 请求那样),那么这可能没关系 - 但如果你需要,你将需要像这个问题的解决方案一样做: 如何使用 WCF 自托管处理 Ajax JQUERY POST 请求 基本上,每个终结点都应该实现:
Webinvoke(Method="OPTIONS", UriTemplate="")
并调用适当的方法,将正确的标头加载到响应中(包括该端点的正确“Access-Control-Allow-Method”列表),以供调用者使用。托管的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");
    }

-3

尝试使用 WebInvoke(Method = "POST") 而不是 WebInvoke(Method = "GET")


没有评论的负面投票?谢谢。 - MindRoasterMir
我认为问题在于你的解决方案实际上并没有解决问题,而且这些动词是针对特定用例设计的,所以当它们不起作用时仅仅切换它们并不是一个好的做法。你的想法可能作为一个临时解决方法可行,但并不是真正的解决方案。 - kling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接