22

我在让 jquery 将一些 json 数据发布到我在 WCF 服务上使用的休息方法时遇到了一些麻烦。

在 WCF 方面,这是操作合同:

[OperationContract]
[WebInvoke(Method = "POST",
           BodyStyle = WebMessageBodyStyle.Bare,
           RequestFormat = WebMessageFormat.Json,
           ResponseFormat = WebMessageFormat.Json,
           UriTemplate = "PostSomething")]
MyResult PostSomething(MyRequest request);

两者MyResultMyRequest标有所有必要的DataContractDataMember属性,并且服务正在公开 WebHttp 端点。

在 JQuery 方面,这是我的函数调用:

var jsonStr = JSON.stringify(reqObj);

$.ajax({
    type: "POST",
    dataType: "json",
    url: "http://localhost/MyService/PostSomething",
    contentType: "application/json; charset=utf-8",
    data: jsonStr,
    success: function (html) {
        alert(html);
    }
});

这个请求永远不会到达我的方法(我每次都得到一个 405 Method Not Allowed),并且在 Charles 中查看请求看起来像这样:

OPTIONS /MyService/PostSomething HTTP/1.1
Host: localhost
Cache-Control: max-age=0
Access-Control-Request-Method: POST
Origin: null
Access-Control-Request-Headers: Content-Type, Accept
Accept: */*
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

一些奇怪的事情:

  1. 该方法是 OPTIONS 而不是 POST
  2. 内容类型(在另一个选项卡中)显示text/html; charset=UTF-8而不是 json
  3. JSON数据无处可见

但是,如果我在 Charles 中修改请求,使其标头与此处的解决方案相似,那么一切正常:

POST /MyService/PostSomething HTTP/1.1
Content-Type: application/json; charset=utf-8
Host: localhost
Content-Length: 152

{"Id":"", "Name":"testspot","Description":"test" } 

在这里查看教程和其他问题,其他人设法让 JQuery 发布到这样的 WCF REST 方法,我不知道我在这里做错了什么。

哦,举个例子,这是一个 WCF 4 服务,我使用的是 JQuery 1.4.4。

谢谢,

更新:

在阅读了更多内容并感谢 Darrel 将我指向跨域规范之后,我设法通过在服务接口上对我的服务进行一些小的更改来进一步了解:

[OperationContract]
[WebInvoke(Method = "*",
           BodyStyle = WebMessageBodyStyle.Bare,
           RequestFormat = WebMessageFormat.Json,
           ResponseFormat = WebMessageFormat.Json,
           UriTemplate = "PostSomething")]
MyResult PostSomething(MyRequest request);

在实现中,我需要检查传入的请求是否针对 OPTIONS 并在这种情况下返回一些标头而不是执行预期的工作:

if (WebOperationContext.Current.IncomingRequest.Method == "OPTIONS")
{
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST");
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept");

    return null;
}

然后该方法被调用两次,第一次服务器返回 null 但向客户端添加一些标头,然后使用 POST 作为方法发出实际请求,服务器继续正常处理请求。

4

5 回答 5

8

这似乎是 Firefox 避免跨域调用的原因。见http://www.petefreitag.com/item/703.cfm

这方面的规范在这里http://www.w3.org/TR/cors/并且经过非常简短的阅读后,似乎因为您正在进行跨域调用,您的服务应该实现 OPTIONS 方法并返回一些允许发送 POST 方法的标头。

于 2011-02-02T14:43:26.327 回答
3

包含建议解决方案的问题的更新存在一些问题 - 问题在于,如果您的输入不支持 POST 方法,则 OPTIONS 请求实际上并未返回正确的允许标头。它实际上并没有查看 WCF 端点上实际允许哪些方法 - 它只是在客户端执行 OPTIONS 请求时人为地说应用程序中的每个端点都允许“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");
    }

除此之外,您应该在 web.config 中为绑定端点设置“CrossDomainScriptAccessEnabled”标志,或者在配置端点时在 WebHttpBinding 的代码中设置。否则,当您说“Access-Control-Allow-Origin”是“*”(或 URL 列表)时,您再次躺在标题响应中

于 2014-03-17T16:36:59.623 回答
1

更新:

尝试将 .svc 放在 MyService 之后,以便 URL 读取

http://localhost/MyService.svc/PostSomething

前几天我自己也在做这个,在 Rick Strahl 的博客上看到了一篇文章:

http://www.west-wind.com/weblog/posts/324917.aspx

这对我来说完美无缺,所以试一试!

希望有帮助!:)

于 2011-02-02T14:00:28.207 回答
0

在您的 web.config 中,您使用过 webhttpbinding 吗?

只有 webhttpbinding 支持 json。

于 2011-02-02T13:58:58.377 回答
0

我只会发布一个对我有帮助的简短答案,因为其他答案没有。

  • 场景:对 wcf 服务的 ajax 调用。
  • 错误原因:在发送 POST 请求之前来自 ajax 的自动 OPTIONS 请求。我的服务无法处理第一个请求。
  • 解决方案:允许 OPTIONS 请求,并响应它。

你需要做什么:

  1. 将此添加到 web.config:

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

  2. 将此添加到 Global.asax.cs(如果您的解决方案中没有此文件,则通过以下方式创建它:添加新项目 => Visual C# => 全局应用程序类(默认名称为“Global.asax”)):

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
                        HttpContext.Current.Response.End();
    }
    
于 2016-07-15T08:26:47.440 回答