Jquery - Jak zmusić $ .post () do użycia contentType = application / json?

308

Zauważyłem, że podczas używania $ .post () w jquery, domyślnym contentType jest application / x-www-form-urlencoded - kiedy mój kod mvc asp.net musi mieć contentType = application / json

(Zobacz to pytanie, dlaczego muszę używać aplikacji / json: ASPNET MVC - Dlaczego ModelState.IsValid false „Pole x jest wymagane”, gdy to pole ma wartość? )

Jak mogę ustawić $ .post () wysyłanie contentType = application / json? Mam już dużą liczbę funkcji $ .post (), więc nie chcę zmieniać na $ .ajax (), ponieważ zajęłoby to zbyt dużo czasu

Jeśli spróbuję

$.post(url, data, function(), "json") 

Nadal ma contentType = application / x-www-form-urlencoded. Co dokładnie robi parametr „json”, jeśli nie zmienia typu zawartości na json?

Jeśli spróbuję

$.ajaxSetup({
  contentType: "application/json; charset=utf-8"
});

To działa, ale wpływa na każdy mój $ .get i $ .post, który mam i powoduje uszkodzenie niektórych.

Czy jest jakiś sposób, aby zmienić zachowanie $ .post (), aby wysłać contentType = application / json?

JK.
źródło

Odpowiedzi:

70

Myślę, że być może będziesz musiał

1. Zmodyfikuj źródło, aby $ .post zawsze używał typu danych JSON, ponieważ tak naprawdę jest to tylko skrót do wstępnie skonfigurowanego $.ajaxpołączenia

Lub

2. Zdefiniuj własną funkcję narzędzia, która jest skrótem do $.ajaxkonfiguracji, której chcesz użyć

Lub

3.Możesz zastąpić $.post functionwłasną implementacją poprzez łatanie małp.

Typ danych JSON w twoim przykładzie odnosi się do typu danych zwróconego z serwera, a nie do formatu wysłanego na serwer.

Russ Cam
źródło
5
+1, wybrałbym definicję nowej metody lub jQuery.postmetodę zastępowania , to naprawdę prosta funkcja ...
CMS
3
To nie jest zły pomysł, po prostu stwórz metodę o nazwie $ .mvcpost (), która robi to samo co $ .post (poprzez skopiowanie połączonego kodu) plus zmienia typ zawartości. Następnie dla wszystkich $ .post (), które muszą zostać zmienione, muszę tylko wpisać 3 dodatkowe znaki z przodu. Jest to o wiele szybsze niż przepisywanie ich jako $ .ajax ().
JK.
9
@PavelRepin, musiałem wywołać JSON.stringify () na ładunku.
Ustaman Sangat
2
@dragon - oto 3 rozwiązania dla „czy jest jakiś sposób, aby zmienić zachowanie $ .post (), aby wysłać contentType = application / json?”. Która część nie jest odpowiedzią?
Russ Cam
2
Ważne jest również, aby wiedzieć: $ .ajax i różne metody spróbują odgadnąć, jaki powinien być contentType (chyba że jest określony) na podstawie danych, które mu podasz. "mystring data"będzie application/x-www-form-urlencoded;tam, gdzie { anyKey: "anyvalue and type" }będzie obiekt application/json. Wiele serwerów, które odczytują json, zezwalają tylko na obiekt lub tablicę, a nie na ciąg znaków - dlatego jquery przewiduje to w ten sposób. Jeśli masz serwer, który odczytuje ciągi, liczby itp. Bez zawijania się w obiekcie, musisz określić typ zawartości jak w tej odpowiedzi.
bzuillsmith,
395
$.ajax({
  url:url,
  type:"POST",
  data:data,
  contentType:"application/json; charset=utf-8",
  dataType:"json",
  success: function(){
    ...
  }
})

Zobacz: jQuery.ajax ()

Adrien
źródło
13
Oryginalny post pyta: „Więc jest jakiś sposób, że mogę zmienić zachowanie $ .post (), aby wysłać contentType = application / json?” Ale mówi też: „To działa, ale wpływa na każdy $ .get i $ .post, który mam i powoduje uszkodzenie niektórych.”. Rozumiem pytanie jako „w jaki sposób mogę osiągnąć to samo, co przy użyciu $ .post, ale wysyłam odpowiedni contentType bez przerywania innych wystąpień $ .get i $ .post”. Czy to nieprawda?
Adrien
5
@ x1a4 wyraźnie nie rozumie, że .ajax jest wezwanie, nie ajaxSetup
Walker
39
@Adrien, na ile warte są dwa lata później, twoja jest odpowiedzią, której szukałem, kiedy googlowałem.
AwesomeTown
74
musiał użyć JSON.stringify(data), ponieważ serwer oczekuje łańcucha JSON, a jQuery po prostu połączy pary klucz-wartość za pomocą ampersandu, urlencododowany.
smok
3
Nawet cztery lata później ta odpowiedź rozwiązała moje godziny poszukiwań za pomocą mniej niż dziesięciu wierszy kodu.
Pieter VDE,
86

W końcu znalazłem rozwiązanie, które działa dla mnie:

jQuery.ajax ({
    url: myurl,
    type: "POST",
    data: JSON.stringify({data:"test"}),
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function(){
        //
    }
});
vvkatwss vvkatwss
źródło
8
Nie udało mi się zrozumieć, dlaczego ciągle pojawiają się błędy, okazuje się, że musisz skreślić dane.
FriendlyGuy,
5
Wiem, że to działa, ale DLACZEGO, dlaczego DLACZEGO trzeba skreślić? Czy to błąd jQuery? Wydaje się, że jest bardzo szczęśliwy, aby serializować dataargument x-www-form-urlencoded, ale jeśli wskażesz, że typ treści żądania to JSON, nadal nalega na wysłanie dataw niedopasowanym formacie.
Pavel Repin
Dobrze. Nie kopałem zbyt wiele. Byłem szczęśliwy, że to działało. ;) Mój serwer wymaga JSON.
vvkatwss vvkatwss
To samo tutaj. Bez JSON.stringify to nie działa, zastanawiam się dlaczego.
John Simoes
42

W moim skrypcie dodałem następującą metodę do jQuery:

jQuery["postJSON"] = function( url, data, callback ) {
    // shift arguments if data argument was omitted
    if ( jQuery.isFunction( data ) ) {
        callback = data;
        data = undefined;
    }

    return jQuery.ajax({
        url: url,
        type: "POST",
        contentType:"application/json; charset=utf-8",
        dataType: "json",
        data: data,
        success: callback
    });
};

I z niego korzystać

$.postJSON('http://url', {data: 'goes', here: 'yey'}, function (data, status, xhr) {
    alert('Nailed it!')
});

Dokonano tego, po prostu kopiując kod „get” i „post” z oryginalnych źródeł JQuery i zapisując kilka parametrów w celu wymuszenia JSON POST.

Dzięki!

ciągłość
źródło
2
Jak zwykle - najlepsza odpowiedź jest na końcu imprezy i ma najmniej pozytywnych głosów; (
nikib3ro
Świetna odpowiedź - trochę czasu zajmuje uświadomienie sobie, że $ .post nie robi tego „po wyjęciu z pudełka”.
markp3rry
21

użyj tylko

jQuery.ajax ({
    url: myurl,
    type: "POST",
    data: mydata,
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function(){
        //
    }
});

ZAKTUALIZOWANO @JK: Jeśli w swoim pytaniu piszesz tylko jeden przykład kodu z $ .post, znajdziesz jeden odpowiadający przykład w odpowiedzi. Nie chcę powtarzać tych samych informacji, które już studiowałeś, dopóki się nie dowiem: $ .post i $ .get to krótkie formy $ .ajax. Więc po prostu użyj $ .ajax i możesz użyć pełnego zestawu jego parametrów bez konieczności zmiany jakichkolwiek ustawień globalnych.

Nawiasem mówiąc, nie polecam zastępowania standardowego $ .post. To moja osobista opinia , ale dla mnie ważne jest nie tylko to, że program działa, ale także to, że wszyscy, którzy czytają twój program, rozumieją go w ten sam sposób. Zastąpienie standardowych metod bez bardzo ważnego powodu może prowadzić do nieporozumień podczas odczytywania kodu programu. Więc powtarzam moje zalecenie jeszcze raz: po prostu użyć oryginalnego jQuery $ .ajax zamiast tworzyć jQuery.geti jQuery.posti odbierać programy, które nie tylko doskonale pracy, ale mogą być odczytywane przez ludzi bez jakichkolwiek nieporozumień.

Oleg
źródło
1
Świetne wyjaśnienie i wytyczne
Ved Prakash,
8

Typ danych „json”, który można przekazać jako ostatni parametr do post () wskazuje, jakiego typu danych oczekuje funkcja w odpowiedzi serwera, a nie jaki typ wysyła w żądaniu. W szczególności ustawia nagłówek „Accept”.

Szczerze mówiąc, najlepszym rozwiązaniem jest przejście na wywołanie ajax (). Funkcja post () jest pomyślana jako wygoda; uproszczona wersja wywołania ajax (), gdy wykonujesz proste publikowanie formularzy. Nie jesteś

Jeśli naprawdę nie chcesz się przełączać, możesz stworzyć własną funkcję o nazwie powiedzmy xpost (), i po prostu przekształcić podane parametry w parametry dla wywołania jQuery ajax (), z ustawionym typem zawartości. W ten sposób zamiast przepisywania wszystkich funkcji post () na funkcje ajax (), wystarczy zmienić je wszystkie z post na xpost (lub cokolwiek innego).

Jacob Mattison
źródło
Tylko metody $ .post (), które wywołują metodę kontrolera mvc asp.net, wymagają zmiany. Te czysto jquery powinny pozostać niezmienione (autouzupełnianie, diaplog, jqgrid itp.) Miałem nadzieję, że wprowadzę prostą zmianę w odpowiednich $ .post (). Ale wygląda na to, że muszę je przekonwertować na $ .ajax (). Jest to duża i bardzo mocna aplikacja, więc jest ich wiele do zmiany.
JK.
5

Wiem, że to późna odpowiedź, faktycznie mam metodę skrótu, której używam do wysyłania / czytania do / z usług opartych na MS .. działa z MVC, a także ASMX itp ...

Posługiwać się:

$.msajax(
  '/services/someservice.asmx/SomeMethod'
  ,{}  /*empty object for nothing, or object to send as Application/JSON */
  ,function(data,jqXHR) {
    //use the data from the response.
  }
  ,function(err,jqXHR) {
    //additional error handling.
  }
);
//sends a json request to an ASMX or WCF service configured to reply to JSON requests.
(function ($) {
  var tries = 0; //IE9 seems to error out the first ajax call sometimes... will retry up to 5 times

  $.msajax = function (url, data, onSuccess, onError) {
    return $.ajax({
      'type': "POST"
      , 'url': url
      , 'contentType': "application/json"
      , 'dataType': "json"
      , 'data': typeof data == "string" ? data : JSON.stringify(data || {})
      ,beforeSend: function(jqXHR) {
        jqXHR.setRequestHeader("X-MicrosoftAjax","Delta=true");
      }
      , 'complete': function(jqXHR, textStatus) {
        handleResponse(jqXHR, textStatus, onSuccess, onError, function(){
          setTimeout(function(){
            $.msajax(url, data, onSuccess, onError);
          }, 100 * tries); //try again
        });
      }
    });
  }

  $.msajax.defaultErrorMessage = "Error retreiving data.";


  function logError(err, errorHandler, jqXHR) {
    tries = 0; //reset counter - handling error response

    //normalize error message
    if (typeof err == "string") err = { 'Message': err };

    if (console && console.debug && console.dir) {
      console.debug("ERROR processing jQuery.msajax request.");
      console.dir({ 'details': { 'error': err, 'jqXHR':jqXHR } });
    }

    try {
      errorHandler(err, jqXHR);
    } catch (e) {}
    return;
  }


  function handleResponse(jqXHR, textStatus, onSuccess, onError, onRetry) {
    var ret = null;
    var reterr = null;
    try {
      //error from jqXHR
      if (textStatus == "error") {
        var errmsg = $.msajax.defaultErrorMessage || "Error retreiving data.";

        //check for error response from the server
        if (jqXHR.status >= 300 && jqXHR.status < 600) {
          return logError( jqXHR.statusText || msg, onError, jqXHR);
        }

        if (tries++ < 5) return onRetry();

        return logError( msg, onError, jqXHR);
      }

      //not an error response, reset try counter
      tries = 0;

      //check for a redirect from server (usually authentication token expiration).
      if (jqXHR.responseText.indexOf("|pageRedirect||") > 0) {
        location.href = decodeURIComponent(jqXHR.responseText.split("|pageRedirect||")[1].split("|")[0]).split('?')[0];
        return;
      }

      //parse response using ajax enabled parser (if available)
      ret = ((JSON && JSON.parseAjax) || $.parseJSON)(jqXHR.responseText);

      //invalid response
      if (!ret) throw jqXHR.responseText;  

      // d property wrap as of .Net 3.5
      if (ret.d) ret = ret.d;

      //has an error
      reterr = (ret && (ret.error || ret.Error)) || null; //specifically returned an "error"

      if (ret && ret.ExceptionType) { //Microsoft Webservice Exception Response
        reterr = ret
      }

    } catch (err) {
      reterr = {
        'Message': $.msajax.defaultErrorMessage || "Error retreiving data."
        ,'debug': err
      }
    }

    //perform final logic outside try/catch, was catching error in onSuccess/onError callbacks
    if (reterr) {
      logError(reterr, onError, jqXHR);
      return;
    }

    onSuccess(ret, jqXHR);
  }

} (jQuery));

UWAGA: Mam również metodę JSON.parseAjax, która jest zmodyfikowana z pliku JS json.org, która dodaje obsługę dat MS „/Date(...)/” ...

Zmodyfikowany plik json2.js nie jest dołączony, w przypadku IE8 używa parsera opartego na skrypcie, ponieważ zdarzają się przypadki, gdy natywny parser ulega awarii podczas rozszerzania prototypu tablicy i / lub obiektu itp.

Zastanawiałem się nad zmianą tego kodu, aby wdrożyć interfejsy obietnic, ale zadziałało to naprawdę dobrze.

Tracker 1
źródło
5

To proste rozszerzenie API jquery (z: https://benjamin-schweizer.de/jquerypostjson.html ) dla $ .postJSON () załatwia sprawę. Możesz używać postJSON () jak każdego innego natywnego wywołania jQuery Ajax. Możesz dołączyć moduły obsługi zdarzeń i tak dalej.

$.postJSON = function(url, data, callback) {
  return jQuery.ajax({
    'type': 'POST',
    'url': url,
    'contentType': 'application/json; charset=utf-8',
    'data': JSON.stringify(data),
    'dataType': 'json',
    'success': callback
  });
};

Podobnie jak inne interfejsy API Ajax (jak $ http z AngularJS) ustawia poprawny contentType na application / json. Możesz przekazać swoje dane Json (obiekty javascript) bezpośrednio, ponieważ są one tutaj rygorystyczne. Oczekiwany zwrócony typ danych jest ustawiony na JSON. Możesz dołączyć domyślne procedury obsługi zdarzeń jquery dla obietnic, na przykład:

$.postJSON(apiURL, jsonData)
 .fail(function(res) {
   console.error(res.responseText);
 })
 .always(function() {
   console.log("FINISHED ajax post, hide the loading throbber");
 });
Ruwen
źródło
4

Sednem sprawy jest fakt, że JQuery w momencie pisania nie ma metody postJSON, podczas gdy getJSON istnieje i robi właściwą rzecz.

metoda postJSON wykonałaby następujące czynności:

postJSON = function(url,data){
    return $.ajax({url:url,data:JSON.stringify(data),type:'POST', contentType:'application/json'});
};

i mogą być używane w następujący sposób:

postJSON( 'path/to/server', my_JS_Object_or_Array )
    .done(function (data) {
        //do something useful with server returned data
        console.log(data);
    })
    .fail(function (response, status) {
        //handle error response
    })
    .always(function(){  
      //do something useful in either case
      //like remove the spinner
    });
dbrin
źródło
1

Dokumentacja obecnie pokazuje, że od 3,0 $ .post zaakceptuje ustawienia obiektu, co oznacza, że można korzystać z opcji $ .ajax. Wersja 3.0 nie została jeszcze wydana, a przy zatwierdzeniu mówią o ukryciu odniesienia do niej w dokumentach, ale poszukaj jej w przyszłości!

Ben Creasy
źródło
1

Miałem podobny problem z następującym kodem JavaScript:

var url = 'http://my-host-name.com/api/Rating';

var rating = { 
  value: 5,
  maxValue: 10
};

$.post(url, JSON.stringify(rating), showSavedNotification);

Gdzie w skrzypku mogłem zobaczyć prośbę z:

  • Nagłówek: Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  • Ciało: {"value":"5","maxValue":"5"}

W rezultacie mój serwer nie mógł zmapować obiektu na typ po stronie serwera.

Po zmianie ostatniego wiersza na ten:

$.post(url, rating, showSavedNotification);

W skrzypaczu wciąż widziałem:

  • Nagłówek: Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  • Ciało: value=5&maxValue=10

Jednak serwer zaczął zwracać to, czego się spodziewałem.

Oleg Burow
źródło
0

Co powiesz na swój własny adapter / opakowanie?

//adapter.js
var adapter = (function() {

return {

    post: function (url, params) {
        adapter.ajax(url, "post", params);
        },
    get: function (url, params) {
        adapter.ajax(url, "get", params);
    },
    put: function (url, params) {
        adapter.ajax(url, "put", params);
    },
    delete: function (url, params) {
        adapter.ajax(url, "delete", params);
    },
    ajax: function (url, type, params) {
        var ajaxOptions = {
            type: type.toUpperCase(),
            url: url,
            success: function (data, status) {
                var msgType = "";
                // checkStatus here if you haven't include data.success = true in your
                // response object
                if ((params.checkStatus && status) || 
                   (data.success && data.success == true)) {
                            msgType = "success";
                            params.onSuccess && params.onSuccess(data);
                    } else {
                            msgType = "danger";
                            params.onError && params.onError(data);
                    }
            },
            error: function (xhr) {
                    params.onXHRError && params.onXHRError();
                    //api.showNotificationWindow(xhr.statusText, "danger");
            }
        };
        if (params.data) ajaxOptions.data = params.data;
        if (api.isJSON(params.data)) {
            ajaxOptions.contentType = "application/json; charset=utf-8";
            ajaxOptions.dataType = "json";
        }
        $.ajax($.extend(ajaxOptions, params.options));
    }
})();

    //api.js
var api = {
  return {
    isJSON: function (json) {
        try {
            var o = JSON.parse(json);
            if (o && typeof o === "object" && o !== null) return true;
        } catch (e) {}
        return false;
    }
  }
})();

I niezwykle proste użycie:

adapter.post("where/to/go", {
    data: JSON.stringify(params),
    onSuccess: function (data) {
        //on success response...
    }
    //, onError: function(data) {  //on error response... }
    //, onXHRError: function(xhr) {  //on XHR error response... }
});
Czernienie
źródło
Próbowałem, ale nadal nie otrzymałem oczekiwanych rezultatów. Mam interfejs API Spring Boot Rest.
Suraj Shingade,
0

Z jakiegoś powodu ustawienie typu zawartości dla żądania ajax jako sugerowanego przez @Adrien nie działa w moim przypadku. Możesz jednak zmienić typ zawartości za pomocą $ .post, robiąc to wcześniej:

$.ajaxSetup({
    'beforeSend' : function(xhr) {
        xhr.overrideMimeType('application/json; charset=utf-8');
    },
});

Następnie $.postzadzwoń:

$.post(url, data, function(), "json")

Miałem problem z jQuery + IIS, i to było jedyne rozwiązanie, które pomogło jQuery zrozumieć, jak używać kodowania Windows-1252 dla żądań ajax.

Johannes
źródło
0

możemy zmienić typ zawartości w ten sposób w $ .post

$ .post (adres URL, dane, funkcja (dane, status, xhr) {xhr.setRequestHeader („Content-type”, „application / x-www-form-urlencoded; charset = utf-8”);});

Snziv Gupta
źródło
-1

$ .post nie działa, jeśli masz problem z CORS (Cross Origin Resource Sharing). Spróbuj użyć $ .Ajax w następującym formacie: „$ .ajax ({url: someurl, contentType: 'application / json', data: requestInJSONFormat, nagłówki: {'Access-Control-Allow-Origin': '*'}, dataType: 'json', typ: 'POST', async: false, success: function (Data) {...}}); "

Soma Sarkar
źródło
-19

Nie możesz wysłać application/jsonbezpośrednio - musi to być parametr żądania GET / POST.

Coś w stylu

$.post(url, {json: "...json..."}, function());
Amy B.
źródło
Ta odpowiedź może być niepoprawna, ale nie jest niskiej jakości i jest próbą odpowiedzi na pytanie. Z recenzji .
Wai Ha Lee