将 JSON 数据从 JQuery 发送到 WCF REST 方法时出现问题

Posted

技术标签:

【中文标题】将 JSON 数据从 JQuery 发送到 WCF REST 方法时出现问题【英文标题】:Problem sending JSON data from JQuery to WCF REST method 【发布时间】:2011-06-19 23:58: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

一些奇怪的事情:

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

但是,如果我修改 Charles 中的请求,使其标头类似于解决方案 here,那么一切正常:

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="*" 才能使事情正常进行。在我的情况下,该方法没有被调用两次! 这里似乎行不通。你能把一个完整的例子放到网上吗? 【参考方案1】:

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

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

【讨论】:

谢谢!对于为什么请求看起来与我的预期如此不同,这听起来像是一个合理的解释。 您知道我需要在 WCF 服务或 JQuery 中进行哪些更改才能使其正常工作吗? @theburningmonk 你需要为 OPTIONS 实现一个处理程序 @DarrelMiller。如何实现 OPTIONS 的处理程序?【参考方案2】:

包含建议解决方案的问题的更新存在一些问题 - 问题在于,如果您的输入不支持 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 列表)时,您再次躺在标题响应中

【讨论】:

您先生,帮了我很多忙。谢谢你:)【参考方案3】:

更新:

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

http://localhost/MyService.svc/PostSomething

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

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

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

希望对您有所帮助! :)

【讨论】:

浏览文章,我在做同样的事情,唯一的区别是当他切换到传递实际数据而不是 json 序列化字符串时 似乎更进一步,调用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 日期:2011 年 2 月 2 日星期三 15:44:55 GMT 内容长度:0 但没有后续调用实际方法【参考方案4】:

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

只有 webhttpbinding 支持 json。

【讨论】:

不走运,只是将方法的位置移动到 localhost/MyService/MyService/PostSomething【参考方案5】:

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

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

你需要做什么:

    将此添加到 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>
    

    将此添加到 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();
    
    

【讨论】:

以上是关于将 JSON 数据从 JQuery 发送到 WCF REST 方法时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

jQuery - 使用 ajax 调用将 JSON 发送到 WCF 服务为空

使用日期将 JQuery JSON 发送到 WCF REST

从 jquery 向 wcf webservice 发送数据

WCF POST 通过 JQuery。如何在 JSON 中发送数组?

WCF从角度发布Json

从 WCF 服务向网站发送数据