Nie można ustawić typu zawartości na „application / json” w jQuery.ajax

106

Kiedy mam ten kod

$.ajax({
    type: 'POST',
    //contentType: "application/json",
    url: 'http://localhost:16329/Hello',
    data: { name: 'norm' },
    dataType: 'json'
});

w aplikacji Fiddler widzę następujące surowe żądanie

POST http://localhost:16329/Hello HTTP/1.1
Host: localhost:16329
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://localhost:14693/WebSite1/index.html
Content-Length: 9
Origin: http://localhost:14693
Pragma: no-cache
Cache-Control: no-cache

name=norm

Ale próbuję ustawić typ zawartości z application / x-www-form-urlencoded na application / json . Ale ten kod

$.ajax({
    type: "POST",
    contentType: "application/json",
    url: 'http://localhost:16329/Hello',
    data: { name: 'norm' },
    dataType: "json"
});

Generuje dziwne żądanie (które widzę w Fiddlerze)

OPTIONS http://localhost:16329/Hello HTTP/1.1
Host: localhost:16329
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Origin: http://localhost:14693
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Pragma: no-cache
Cache-Control: no-cache

Dlaczego? Co to jest OPCJE, kiedy powinno tam być POST? A gdzie mój typ zawartości jest ustawiony na application / json? Parametry żądania zniknęły z jakiegoś powodu.

AKTUALIZACJA 1

Po stronie serwera mam naprawdę prostą usługę RESTful.

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class RestfulService : IRestfulService
{
    [WebInvoke(
        Method = "POST",
        UriTemplate = "Hello",
        ResponseFormat = WebMessageFormat.Json)]
    public string HelloWorld(string name)
    {
        return "hello, " + name;
    }
}

Ale z jakiegoś powodu nie mogę wywołać tej metody z parametrami.

AKTUALIZACJA 2

Przepraszam, że nie odpowiadałem tak długo.

Dodałem te nagłówki do mojej odpowiedzi serwera

 Access-Control-Allow-Origin: *
 Access-Control-Allow-Headers: Content-Type
 Access-Control-Allow-Methods: POST, GET, OPTIONS

To nie pomogło, mam metodę niedozwoloną błąd z serwera.

Oto, co mówi mój skrzypek

wprowadź opis obrazu tutaj

Więc teraz mam pewność, że mój serwer akceptuje POST, GET, OPTIONS (jeśli nagłówki odpowiedzi działają zgodnie z oczekiwaniami). Ale dlaczego „Metoda niedozwolona”?

W WebView odpowiedź z serwera (widać odpowiedź Raw na powyższym obrazku) wygląda tak

wprowadź opis obrazu tutaj

Vitalii Korsakov
źródło
2
powinieneś wypróbować metodę JSON.stringfy ()
Amritpal Singh
Popatrz tutaj. U mnie to działa bardzo dobrze: stackoverflow.com/questions/9754767/ ...
Fanda
Mam dokładnie ten sam problem, ale pracuję z NodeJS jako zapleczem, a także ustawiam wszystkie żądania OPTION nie tylko tak, aby były akceptowane, ale wymuszam odpowiedź 200 na wszystkie żądania OPTION, więc reszta petycji działa zgodnie z oczekiwaniami bez odpowiedzi ...
HeberLZ
1
Cześć @VitaliiKorsakov. Czy rozwiązałeś swój problem? Mam ten sam problem, tj. Nie mogę zmodyfikować contentType.
worldterminator
1
Miałem ten sam problem i właśnie to działało… rozwiązanie jest w odpowiedzi na tej stronie: stackoverflow.com/questions/20295080/… .. podsumowując: „Używając contentType: 'application / json' będziesz nie można polegać na wypełnianiu $ _POST. $ _POST jest wypełniane tylko dla typów treści zakodowanych w formie. W związku z tym musisz odczytać dane z surowego wejścia PHP ".. Widzę, że teraz nie używasz php na serwerze ale miejmy nadzieję, że ta informacja w jakiś sposób pomoże.
Sarah

Odpowiedzi:

91

Wydawałoby się, że usunięcie http:// z opcji url zapewnia wysłanie prawidłowego nagłówka HTTP POST.

Nie sądzę, abyś musiał w pełni kwalifikować nazwę hosta, po prostu użyj względnego adresu URL, jak poniżej.

   $.ajax({
      type: "POST",
      contentType: "application/json",
      url: '/Hello',
      data: { name: 'norm' },
      dataType: "json"
   });

Mój przykład, który działa:

        $.ajax({
            type: "POST",
            url: siteRoot + "api/SpaceGame/AddPlayer",
            async: false,
            data: JSON.stringify({ Name: playersShip.name, Credits: playersShip.credits }),
            contentType: "application/json",
            complete: function (data) {
            console.log(data);
            wait = false;
        }
    });

Prawdopodobnie powiązane: jQuery $ .ajax (), $ .post wysyłające „OPTIONS” jako REQUEST_METHOD w przeglądarce Firefox

Edycja: Po kilku dalszych poszukiwaniach odkryłem, że nagłówek OPTIONS jest używany do sprawdzenia, czy żądanie z domeny źródłowej jest dozwolone. Korzystając z narzędzia Fiddler, dodałem następujące informacje do nagłówków odpowiedzi z mojego serwera.

 Access-Control-Allow-Origin: *
 Access-Control-Allow-Headers: Content-Type
 Access-Control-Allow-Methods: POST, GET, OPTIONS

Gdy przeglądarka otrzymała tę odpowiedź, wysłała prawidłowe żądanie POST z danymi json. Wydawałoby się, że domyślny typ zawartości w formacie form-urlencoded jest uważany za bezpieczny i dlatego nie podlega dodatkowym kontrolom międzydomenowym.

Wygląda na to, że będziesz musiał dodać wspomniane wcześniej nagłówki do odpowiedzi serwera na żądanie OPTIONS. Powinieneś oczywiście skonfigurować je tak, aby zezwalały na żądania z określonych domen, a nie wszystkich.

Użyłem następującego jQuery, aby to przetestować.

$.ajax({
   type: "POST",
   url: "http://myDomain.com/path/AddPlayer",
   data: JSON.stringify({
      Name: "Test",
       Credits: 0
   }),
   //contentType: "application/json",
   dataType: 'json',
   complete: function(data) {
       $("content").html(data);
  }
});​

Bibliografia:

Mike Wade
źródło
Chcę stracić połączenie między klientem a serwerem. Serwer jest usługą zgodną z REST i wszyscy klienci tej usługi powinni znać jej adres URL.
Vitalii Korsakov
Czy możesz podać więcej szczegółów w swoim poście na temat scenariusza tego pytania? Jeśli Twoi klienci będą w różnych domenach, możesz napotkać problemy z tym samym pochodzeniem.
Mike Wade,
Opublikowałem dodatkowe informacje o stronie serwera. W tej chwili serwer i klient są na hoście lokalnym, ale różnią się portem. Później najprawdopodobniej będą w różnych domenach.
Vitalii Korsakov
Wygląda na to, że problem, który napotykasz, jest związany z tą samą polityką pochodzenia, warto spojrzeć na jsonp i pytanie, do którego dołączyłem w mojej odpowiedzi, oprócz pytania związanego z tymi linkami . jquery cross domain guide - nie mam dużego doświadczenia z żądaniami międzydomenowymi, ale mam nadzieję, że te linki okażą się przydatne.
Mike Wade,
Nie sądzę, żeby to był problem, ponieważ wszystko działa dobrze, gdy nie przekazuję żadnych parametrów, a typ zawartości to application / x-www-form-urlencoded. Ale nie potrzebuję żądania POST, jeśli nie mogę przekazać żadnych parametrów.
Vitalii Korsakov
41

Mogę ci pokazać, jak to wykorzystałem

  function GetDenierValue() {
        var denierid = $("#productDenierid").val() == '' ? 0 : $("#productDenierid").val();
        var param = { 'productDenierid': denierid };
        $.ajax({
            url: "/Admin/ProductComposition/GetDenierValue",
            dataType: "json",
            contentType: "application/json;charset=utf-8",
            type: "POST",
            data: JSON.stringify(param),
            success: function (msg) {
                if (msg != null) {
                    return msg.URL;
                }
            }
        });
    }
Amritpal Singh
źródło
To samo, co w następnej odpowiedzi. Nie mogę nie podać adresu URL do serwera, na którym hostowane są wszystkie funkcje usługi
Vitalii Korsakov
@VitaliiKorsakov Odszedłem, rozwiązałeś swój problem.
Amritpal Singh
Dziękuję za odpowiedź! Nie mogę uwierzyć, że to nie zostało napisane gdzie indziej. Na pewno wygląda na to, że JQuery opublikowałby plik json, gdy określony typ to „json”, ale chyba nie ...
Jason Goemaat
1
@JasonGoemaat parametr dataType w jQuery jest używany tylko do analizowania zwróconej treści odpowiedzi. Jeśli przeczytasz dokumentację, zobaczysz, że nie jest nawet potrzebna. Domyślną wartością dataType jest inteligentne przypuszczenie. Twój problem polega na tym, że atrybut danych w jquery nie jest konfigurowalny. Nie możesz powiedzieć, jak jquery ma analizować obiekt danych. Dlatego wcześniej musisz serializować json. Ponieważ jquery serializuje się tylko do kodowania postaci url
Loïc Faure-Lacroix
12

Więc wszystko, co musisz zrobić, aby to zadziałało, to dodać:

headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
}

jako pole do żądania wpisu i zadziała.

Cody Jacques
źródło
api.jquery.com/jquery.ajax Jeśli zajrzysz do dokumentacji, zobaczysz, że bez określenia wartości domyślnej jest to „application / x-www-form-urlencoded; charset = UTF-8 '(i dlatego tak się dzieje. Nie wiem, dlaczego samo ustawienie contentType nie działa. Możesz sprawdzić, jaką masz wersję jQuery i zaktualizować, jeśli używasz starej wersji).
Cody Jacques,
To nie działa. Chociaż mam type: "POST", to wysyła OPTIONS.
user9645
5

Rozpoznałem te ekrany, używam CodeFluentEntities i mam rozwiązanie, które również mi się sprawdziło.

Używam tej konstrukcji:

$.ajax({
   url: path,
   type: "POST",
   contentType: "text/plain",
   data: {"some":"some"}
}

jak widać, jeśli używam

contentType: "",

lub

contentType: "text/plain", //chrome

Wszystko dziala.

Nie jestem w 100% pewien, czy to wszystko, czego potrzebujesz, ponieważ zmieniłem też nagłówki.

Alexey Avdeyev
źródło
5

Jeśli używasz tego:

contentType: "application/json"

AJAX nie wyśle ​​parametrów GET lub POST do serwera ... nie wiem dlaczego.

Dziś godzinami zajęło mi nauczenie się tego.

Po prostu użyj:

$.ajax(
  { url : 'http://blabla.com/wsGetReport.php',
    data : myFormData, type : 'POST', dataType : 'json', 
    // contentType: "application/json", 
    success : function(wsQuery) { }
  }
)
Luis Arturo Erique Guajala
źródło
1
niestety poprawna odpowiedź dla mnie. Pomiń contentType i po prostu użyj dataType, aby ominąć śmieci CORS OPTIONS, których wiele usług po prostu nie implementuje poprawnie. Tak denerwujące.
Umopepisdn
2

Tutaj znalazłem rozwiązanie tego problemu . Nie zapomnij zezwolić na OPCJE czasownika w module obsługi aplikacji usług IIS.

Działa w porządku. Dziękuję André Pedroso. :-)

Fanda
źródło
1

Miałem ten sam problem. Uruchamiam aplikację java rest na serwerze jboss. Ale myślę, że rozwiązanie jest podobne w aplikacji internetowej ASP .NET.

Firefox wykonuje wstępne wywołanie do twojego serwera / adresu URL, aby sprawdzić, które opcje są dozwolone. To jest żądanie „OPCJE”, na które Twój serwer nie odpowiada. Jeśli odpowiedź na to wywołanie OPTIONS jest poprawna, wykonywane jest drugie wywołanie, które jest rzeczywistym żądaniem „POST” z zawartością json.

Dzieje się tak tylko podczas wykonywania połączenia między domenami. W Twoim przypadku wywołanie „ http://localhost:16329/Hello” zamiast wywoływania ścieżki adresu URL w tej samej domenie „/ Hello”

Jeśli zamierzasz wykonywać połączenie między domenami, musisz rozszerzyć swoją klasę usług resztowych o metodę z adnotacjami, która obsługuje żądanie http „OPTIONS”. Oto zgodna z implementacją Java:

@Path("/rest")
public class RestfulService {

    @POST
    @Path("/Hello")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.TEXT_PLAIN)
    public string HelloWorld(string name)
    {
        return "hello, " + name;
    }

//THIS NEEDS TO BE ADDED ADDITIONALLY IF MAKING CROSS-DOMAIN CALLS

    @OPTIONS
    @Path("/Hello")
    @Produces(MediaType.TEXT_PLAIN+ ";charset=utf-8")
    public Response checkOptions(){
        return Response.status(200)
        .header("Access-Control-Allow-Origin", "*")
        .header("Access-Control-Allow-Headers", "Content-Type")
        .header("Access-Control-Allow-Methods", "POST, OPTIONS") //CAN BE ENHANCED WITH OTHER HTTP CALL METHODS 
        .build();
    }
}

Więc myślę, że w .NET musisz dodać dodatkową metodę z adnotacją

[WebInvoke(
        Method = "OPTIONS",
        UriTemplate = "Hello",
        ResponseFormat = WebMessageFormat.)]

gdzie ustawiane są następujące nagłówki

.header("Access-Control-Allow-Origin", "*")
        .header("Access-Control-Allow-Headers", "Content-Type")
        .header("Access-Control-Allow-Methods", "POST, OPTIONS")
Vincent
źródło
0

Mam rozwiązanie do wysyłania danych JSON przez żądanie POST przez jquery ajax. Użyłem poniższego kodu

    var data = new Object();
    data.p_clientId = 4;
    data =  JSON.stringify(data);

    $.ajax({
      method: "POST",
      url: "http://192.168.1.141:8090/api/Client_Add",
      data: data,
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'text/plain'
    }
    })
      .done(function( msg ) {
        alert( "Data Saved: " + msg );
      });


        });
    });

Użyłem 'Content-Type': 'text/plain'w nagłówku do wysłania surowych danych json.
Bo jeśli użyjemy Content-Type: 'application/json'metod żądania przekonwertowanych na OPTION, ale użycie Content-Type: 'test/plain'metody nie zostanie przekonwertowane i pozostanie jako POST. Mam nadzieję, że to komuś pomoże.

Rahul Aparajit
źródło
3
Tak naprawdę nie konwertuje się na OPCJĘ, wysyła żądanie inspekcji wstępnej CORS w celu sprawdzenia, czy POST jest dozwolony. Jeśli to nie wróci prawidłowo, POST się nie dzieje.
Umopepisdn
0

Cześć Te dwie linie pracowały dla mnie.

contentType: "application / json; charset = utf-8", dataType: "json"

 $.ajax({
            type: "POST",
            url: "/v1/candidates",
            data: obj,
            **contentType:"application/json; charset=utf-8",
            dataType:"json",**
            success: function (data) {
                table.row.add([
                    data.name, data.title
                ]).draw(false);
            }

Dzięki, Prashant

Prashant Kumar
źródło