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

发布于 10-15 16:26 字数 3103 浏览 8 评论 0 原文

我在让 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 不允许的方法),并且在 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不发布
  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 作为方法发出实际请求,服务器继续正常处理该请求。

I'm having some trouble getting jquery to post some json data to a rest method I have on my WCF service.

On the WCF side, here's the operation contract:

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

both MyResult and MyRequest are marked with all the necessary DataContract and DataMember attributes and service is exposing WebHttp endpoint.

On the JQuery side, here's my function call:

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

this request never reaches my method (I get a 405 Method Not Allowed everytime), and looking in Charles the request looks like this:

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

couple of things which is strange about this:

  1. the method is OPTIONS not POST
  2. the content-type (in another tab) shows text/html; charset=UTF-8 instead of json
  3. the JSON data is no where to be seen

However, if I modify the request in Charles so that its headers is similar to the solution here, then everything works:

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

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

looking at tutorials and other questions on here others have managed to get JQuery to post to a WCF REST method like this, and I'm at a loss as to what I'm doing wrong here..

oh, to put some context, this is a WCF 4 service and I'm using JQuery 1.4.4.

Thanks,

UPDATE:

After some more reading and thanks to Darrel for pointing me towards the cross-domain spec, I managed to get a bit further by making some small changes to my service, on the service interface:

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

and in the implementation, I need to check if the incoming requests is for OPTIONS and in that case return some headers rather than doing the intended work:

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

the method then gets called twice, the first time the server returns null but adds some headers to the client, and then the actual request is made with POST as method and the server goes ahead and deals with the request normally.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

月下客 2024-10-22 16:26:34

这似乎是 Firefox 的一个功能,可以避免跨域调用。请参阅 http://www.petefreitag.com/item/703.cfm

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

This seems to be a Firefox thing for avoiding cross domain calls. See http://www.petefreitag.com/item/703.cfm

The spec for this is here http://www.w3.org/TR/cors/ and after a very brief read, it appears that because you are doing a cross domain call, your service is expected to implement the OPTIONS method and return some headers that allow the POST method to be sent.

岁月无声 2024-10-22 16:26:34

包含建议解决方案的问题的更新存在一些问题 - 问题是,如果您的输入不支持 POST 方法,则 OPTIONS 请求实际上不会返回正确的允许标头。它实际上并没有考虑 WCF 端点上实际允许哪些方法 - 它只是人为地表示当客户端执行 OPTIONS 请求时应用程序中的每个端点都允许“POST”(这实际上是客户端询问支持什么) )。

如果您并不真正依赖 OPTIONS 方法中的信息来返回有效的方法列表(就像某些 CORS 请求的情况),这可能没问题 - 但如果您是这样,您将需要执行类似的操作这个问题的解答:
如何使用 WCF self 处理 Ajax JQUERY POST 请求-host

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

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 的代码中设置“CrossDomainScriptAccessEnabled”标志。否则,当您说“Access-Control-Allow-Origin”是“*”(或 URL 列表)时,您再次在标头响应中撒谎

The update on the question containing a proposed solution has some issues - The problem with it is that if your input does not support the POST method, the OPTIONS request is not actually returning the correct allowed headers. It really isn't looking at which methods are actually allowed on the WCF endpoint - its just artificially saying "POST" is allowed for every single endpoint in the application when a client performs an OPTIONS request (which is really the client asking what is supported).

This is probably OK, if you aren't really relying on the information in the OPTIONS method to return you a valid list of methods (as is the case with some CORS requests) - but if you are, you will need to do something like the solution on this question:
How to handle Ajax JQUERY POST request with WCF self-host

Basically, each endpoint should implement:

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

and call an appropriate method which loads the proper headers to the response (including the proper "Access-Control-Allow-Method" list for that endpoint) to the caller. It kind of sucks that hosted WCF endpoints don't do this for us automatically, but this is a workaround that allows finer control over the endpoint.
In that solution the proper response headers are loaded at the endpoint implementation:

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

In addition to that, you should be setting the "CrossDomainScriptAccessEnabled" flag either in the web.config for the binding endpoint, or in code for the WebHttpBinding when configuring the endpoint. Otherwise, you are again lying in your header response when you say "Access-Control-Allow-Origin" is "*" (or a list of URLS)

那请放手 2024-10-22 16:26:34

更新:

尝试将 .svc 放在 MyService 之后,以便 URL 显示

http://localhost/MyService.svc/PostSomething

我前几天自己正在研究这个问题,并在 Rick Strahl 的博客上看到了一篇文章:

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

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

希望有帮助! :)

Update:

Try putting .svc after MyService so that the URL reads

http://localhost/MyService.svc/PostSomething

I was working on this the other day myself, and came across a post on Rick Strahl's blog:

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

This works flawlessly for me, so give it a try!

Hope that helps! :)

烧了回忆取暖 2024-10-22 16:26:34

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

仅 webhttpbinding 支持 json。

In your web.config have you used webhttpbinding?

only webhttpbinding supports json.

请止步禁区 2024-10-22 16:26:34

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

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

您需要做什么:

  1. 将其添加到 web.config:

    ;
    
      <自定义标题>
        <添加名称=“Access-Control-Allow-Origin”值=“*”/>
        <添加名称=“Access-Control-Allow-Methods”值=“GET、PUT、POST、DELETE、OPTIONS”/>
        <添加名称=“Access-Control-Allow-Headers”值=“内容类型”/>
      
    
    

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

    protected void Application_BeginRequest(对象发送者,EventArgs e)
    {
        if (HttpContext.Current.Request.HttpMethod == "选项")
                        HttpContext.Current.Response.End();
    }
    

I'll just post a short answer that helped me, because other answers didn't.

  • Scenario: ajax call to wcf service.
  • Error cause: automatic OPTIONS request from ajax before sending POST
    request. The first request could not be handled by my service.
  • Solution: allow OPTIONS request, and respond to it.

What you need to do:

  1. Add this to 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. Add this to Global.asax.cs (if you don't have this file in your solution, then create it by: Add new item => Visual C# => Global Application Class (default name is "Global.asax")):

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
                        HttpContext.Current.Response.End();
    }
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文