Проблема отправки данных JSON из JQuery в метод REST WCF
У меня возникли проблемы с получением jquery для отправки некоторых данных json в метод rest, который есть у меня в службе WCF.
На стороне WCF вот контракт на эксплуатацию:
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "PostSomething")]
MyResult PostSomething(MyRequest request);
и то и другое MyResult
а также MyRequest
отмечены все необходимые DataContract
а также DataMember
Атрибуты и сервис выставляют конечную точку 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 Not Allowed каждый раз), и, глядя на Чарльза, запрос выглядит так:
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
пара вещей, которые странные об этом:
- метод ВАРИАНТЫ, а не ПОСТ
- тип контента (в другой вкладке) показывает
text/html; charset=UTF-8
вместо JSON - данные 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.
Спасибо,
ОБНОВИТЬ:
После дополнительного чтения и благодарности Даррелу за то, что он указал мне на междоменную спецификацию, мне удалось продвинуться немного дальше, внеся некоторые небольшие изменения в мой сервис в интерфейсе сервиса:
[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;
}
затем метод вызывается дважды, в первый раз сервер возвращает ноль, но добавляет некоторые заголовки клиенту, а затем фактический запрос выполняется с помощью метода POST в качестве метода, и сервер продолжает работу и обрабатывает запрос в обычном режиме.
5 ответов
Это похоже на то, что Firefox позволяет избежать междоменных вызовов. См. http://www.petefreitag.com/item/703.cfm
Спецификация для этого находится здесь http://www.w3.org/TR/cors/ и после очень краткого прочтения выясняется, что, поскольку вы делаете междоменный вызов, ваша служба должна реализовать метод OPTIONS и вернуть некоторые заголовки, которые позволяют отправлять метод POST.
В обновлении вопроса, содержащего предлагаемое решение, есть некоторые проблемы. Проблема в том, что если ваш ввод не поддерживает метод POST, запрос OPTIONS фактически не возвращает правильные разрешенные заголовки. На самом деле он не смотрит, какие методы на самом деле разрешены в конечной точке WCF - просто искусственно говорится, что "POST" разрешен для каждой конечной точки в приложении, когда клиент выполняет запрос OPTIONS (который действительно является клиентом, спрашивающим, что поддерживается).).
Это, вероятно, нормально, если вы на самом деле не полагаетесь на информацию в методе OPTIONS, чтобы вернуть вам действительный список методов (как в случае с некоторыми запросами CORS) - но если вы это сделаете, вам нужно будет сделать что-то вроде решение по этому вопросу: как обработать AJAX-запрос JQUERY POST с помощью собственного хоста WCF
По сути, каждая конечная точка должна реализовывать:
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");
}
В дополнение к этому вы должны установить флаг "CrossDomainScriptAccessEnabled" либо в файле web.config для конечной точки привязки, либо в коде для WebHttpBinding при настройке конечной точки. В противном случае вы снова лежите в ответе вашего заголовка, когда говорите, что "Access-Control-Allow-Origin" равен "*" (или список URL-адресов).
Обновить:
Попробуйте поставить.svc после MyService, чтобы URL читался
http://localhost/MyService.svc/PostSomething
Я работал над этим на днях и наткнулся на пост в блоге Рика Строла:
http://www.west-wind.com/weblog/posts/324917.aspx
Это работает для меня безупречно, так что попробуйте!
Надеюсь, это поможет!:)
Я просто опубликую короткий ответ, который помог мне, потому что другие ответы не помогли.
- Сценарий: ajax вызов службы wcf.
- Причина ошибки: автоматический запрос OPTIONS от ajax перед отправкой запроса POST. Первый запрос не может быть обработан моим сервисом.
- Решение: разрешить запрос 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 Application Class (имя по умолчанию - "Global.asax")):
protected void Application_BeginRequest(object sender, EventArgs e) { if (HttpContext.Current.Request.HttpMethod == "OPTIONS") HttpContext.Current.Response.End(); }
В вашем web.config вы использовали webhttpbinding?
только webhttpbinding поддерживает JSON.