将 JSON 数据从 JQuery 发送到 WCF REST 方法时出现问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4875195/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Problem sending JSON data from JQuery to WCF REST method
提问by theburningmonk
I'm having some trouble getting jquery to post some json data to a rest method I have on my WCF service.
我在让 jquery 将一些 json 数据发布到我的 WCF 服务上的休息方法时遇到了一些麻烦。
On the WCF side, here's the operation contract:
在WCF方面,这里是操作合同:
[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.
双方MyResult
并MyRequest
标有所有必要DataContract
和DataMember
属性和服务暴露WebHttp端点。
On the JQuery side, here's my function call:
在 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);
}
});
this request never reaches my method (I get a 405 Method Not Allowed everytime), and looking in Charles the request looks like this:
这个请求永远不会到达我的方法(我每次都得到一个 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
couple of things which is strange about this:
有几件事很奇怪:
- the method is OPTIONS not POST
- the content-type (in another tab) shows
text/html; charset=UTF-8
instead of json - the JSON data is no where to be seen
- 该方法是 OPTIONS 而不是 POST
- 内容类型(在另一个选项卡中)显示
text/html; charset=UTF-8
而不是 json - JSON 数据无处可见
However, if I modify the request in Charles so that its headers is similar to the solution here, then everything works:
但是,如果我修改 Charles 中的请求,使其标头类似于此处的解决方案,则一切正常:
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..
看看这里的教程和其他问题,其他人已经设法让 JQuery 发布到这样的 WCF REST 方法,我不知道我在这里做错了什么..
oh, to put some context, this is a WCF 4 service and I'm using JQuery 1.4.4.
哦,说一下上下文,这是一个 WCF 4 服务,我使用的是 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:
经过更多阅读并感谢 Darrel 将我指向跨域规范,我设法通过在服务界面上对我的服务进行了一些小的更改来更进一步:
[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:
在实现中,我需要检查传入的请求是否针对 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;
}
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.
然后该方法被调用两次,第一次服务器返回 null 但向客户端添加一些标头,然后使用 POST 作为方法发出实际请求,服务器继续并正常处理请求。
采纳答案by Darrel Miller
This seems to be a Firefox thing for avoiding cross domain calls. See http://www.petefreitag.com/item/703.cfm
这似乎是 Firefox 避免跨域调用的事情。见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.
这个规范在这里http://www.w3.org/TR/cors/并且经过非常简短的阅读后,似乎因为您正在进行跨域调用,您的服务应该实现 OPTIONS 方法并返回一些允许发送 POST 方法的标头。
回答by jeremyh
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).
包含建议解决方案的问题的更新存在一些问题 - 问题在于,如果您的输入不支持 POST 方法,则 OPTIONS 请求实际上不会返回正确的允许标头。它真的不是在查看 WCF 端点上实际允许哪些方法 - 它只是人为地说当客户端执行 OPTIONS 请求时应用程序中的每个端点都允许“POST”(这实际上是客户端询问支持什么)。
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
这可能没问题,如果您不是真的依赖 OPTIONS 方法中的信息来返回有效的方法列表(如某些 CORS 请求的情况)-但如果是,则需要执行以下操作这个问题的解决方案: How to handle Ajax JQUERY POST request with WCF self-host
Basically, each endpoint should implement:
基本上,每个端点都应该实现:
Webinvoke(Method="OPTIONS", UriTemplate="")
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:
并调用适当的方法,该方法将正确的标头加载到响应中(包括该端点的正确“访问控制允许方法”列表)给调用者。托管的 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");
}
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)
除此之外,您应该在 web.config 中为绑定端点设置“CrossDomainScriptAccessEnabled”标志,或者在配置端点时在 WebHttpBinding 的代码中设置。否则,当您说“Access-Control-Allow-Origin”为“*”(或 URL 列表)时,您将再次躺在标头响应中
回答by Yngve B-Nilsen
Update:
更新:
Try putting .svc after MyService so that the URL reads
尝试将 .svc 放在 MyService 之后,以便 URL 读取
http://localhost/MyService.svc/PostSomething
I was working on this the other day myself, and came across a post on Rick Strahl's blog:
前几天我自己也在做这个,在 Rick Strahl 的博客上看到了一篇文章:
http://www.west-wind.com/weblog/posts/324917.aspx
http://www.west-wind.com/weblog/posts/324917.aspx
This works flawlessly for me, so give it a try!
这对我来说完美无缺,所以试试吧!
Hope that helps! :)
希望有帮助!:)
回答by alexkovelsky
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.
- 场景:ajax 调用 wcf 服务。
- 错误原因:在发送 POST 请求之前来自 ajax 的自动 OPTIONS 请求。我的服务无法处理第一个请求。
- 解决方案:允许 OPTIONS 请求,并响应它。
What you need to do:
你需要做什么:
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>
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(); }
将此添加到 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(); }
回答by Shiraz Bhaiji
In your web.config have you used webhttpbinding?
在你的 web.config 中你使用过 webhttpbinding 吗?
only webhttpbinding supports json.
只有 webhttpbinding 支持 json。