Проблема отправки данных JSON из JQuery в метод REST WCF - PullRequest
22 голосов
/ 02 февраля 2011

У меня возникли проблемы с получением 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

Пара вещей, которые странны по этому поводу:

  1. метод не ПОСТ
  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.

Спасибо

UPDATE:

После некоторого прочтения и благодарности Даррелу за то, что он указал мне на междоменную спецификацию, мне удалось продвинуться немного дальше, внеся небольшие изменения в мой сервис в интерфейсе сервиса:

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

и в реализации мне нужно проверить, относятся ли входящие запросы к ОПЦИЯМ, и в этом случае вернуть некоторые заголовки, а не выполнять намеченную работу:

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 ]

8 голосов
/ 02 февраля 2011

Это похоже на то, что Firefox избегает междоменных вызовов.См. http://www.petefreitag.com/item/703.cfm

. Спецификация для этого здесь http://www.w3.org/TR/cors/, и после очень краткого чтения кажется, что, поскольку вы делаете междоменный вызов, ваша служба должна реализовать метод OPTIONSи вернуть некоторые заголовки, которые позволяют отправлять метод POST.

3 голосов
/ 17 марта 2014

В обновлении вопроса, содержащего предлагаемое решение, есть некоторые проблемы. Проблема в том, что если ваш ввод не поддерживает метод 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-адресов)

1 голос
/ 02 февраля 2011

Обновление:

Попробуйте поставить .svc после MyService, чтобы URL читался как

http://localhost/MyService.svc/PostSomething

Я работал над этим на днях и наткнулся на сообщение оБлог Рика Страла:

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

Это работает безупречно для меня, так что попробуйте!1014 *

Надеюсь, это поможет!:)

0 голосов
/ 15 июля 2016

Я просто опубликую короткий ответ, который помог мне, потому что другие ответы не помогли.

  • Сценарий: ajax-вызов службы wcf.
  • Причина ошибки: автоматический запрос OPTIONS от ajax перед отправкой POST запрос. Первый запрос не может быть обработан моим сервисом.
  • Решение: разрешить запрос 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 Application Class (по умолчанию имя «Global»). .asax ")):

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
                        HttpContext.Current.Response.End();
    }
    
0 голосов
/ 02 февраля 2011

В вашем web.config вы использовали webhttpbinding?

только webhttpbinding поддерживает json.

...