使用JQuery发送JSON数据到WCF REST方法出现问题

22

我遇到了一些问题,无法让jquery将一些json数据发布到我的WCF服务上的rest方法。

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

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

我使用了具有所有必要的 DataContractDataMember 属性标记的 MyResultMyRequest, 并且服务正在公开 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作为方法进行实际请求,服务器继续正常处理该请求。


我非常爱你!非常!!!干杯!我必须在Windows服务应用程序中托管WCF。 GET方法可以运行,但POST从未工作过,直到我使用了Method="*"才使事情正常。 在我的情况下,该方法没有被调用两次! - Eduardo Xavier
这里好像不起作用.. 你能把完整的示例放到网上吗? - K-Dawg
5个回答

8

谢谢!这听起来像是一个合理的解释,解释了为什么请求看起来与我预期的如此不同。 - theburningmonk
你知道我需要在我的WCF服务或JQuery中做哪些更改才能让它正常工作吗? - theburningmonk
@theburningmonk 你需要实现一个 OPTIONS 处理程序。 - Darrel Miller
3
如何实现 OPTIONS 的处理程序? - Hodaya Shalom

3
包含建议解决方案的问题更新存在一些问题——它的问题在于,如果您的输入不支持POST方法,则OPTIONS请求实际上并没有返回正确的允许头信息。它并没有真正查看WCF端点上实际允许使用哪些方法,而是人为地认为每个应用程序中的终结点都允许"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");
    }

此外,您还应该在绑定端点的web.config中设置“CrossDomainScriptAccessEnabled”标志,或在配置端点时对WebHttpBinding进行代码设置。否则,当您说“Access-Control-Allow-Origin”为“*”(或URL列表)时,您的头部响应仍然是错误的。

您先生,您刚刚帮了我很多。谢谢 :) - djfranzwa

1

更新:

尝试在MyService后面加上“.svc”,使URL变为

http://localhost/MyService.svc/PostSomething

前几天我自己也在处理这个问题,然后看到了Rick Strahl博客上的一篇文章:

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

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

希望能帮到你!:)


浏览了一下这篇文章,我正在做完全相同的事情,唯一的区别是当他切换到传递实际数据而不是JSON序列化字符串时。 - theburningmonk
似乎有一些进展,调用http://localhost/MyService.svc/PostSomething返回:HTTP/1.1 200 OK 允许: OPTIONS、TRACE、GET、HEAD、POST 服务器: Microsoft-IIS/7.5 公共: OPTIONS、TRACE、GET、HEAD、POST X-Powered-By: ASP.NET 日期: Wed, 02 Feb 2011 15:44:55 GMT 内容长度: 0 但是没有对实际方法的后续调用。 - theburningmonk

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

0

你的 web.config 文件中是否使用了 webhttpbinding?

只有 webhttpbinding 支持 json。


没有运气,那只是将该方法的位置移动到localhost/MyService/MyService/PostSomething。 - theburningmonk

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