Как заставить $ .post () использовать contentType = application / json?

309

Я заметил, что при использовании $ .post () в jquery по умолчанию contentType является application / x-www-form-urlencoded - когда мой код mvc asp.net должен иметь contentType = application / json

(См. Этот вопрос, чтобы узнать, почему я должен использовать application / json: ASPNET MVC. Почему ModelState.IsValid имеет значение «Поле x обязательно», если это поле имеет значение? )

Как я могу заставить $ .post () отправлять contentType = application / json? У меня уже есть большое количество функций $ .post (), поэтому я не хочу переходить на $ .ajax (), потому что это займет слишком много времени

Если я попробую

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

Он все еще имеет contentType = application / x-www-form-urlencoded. Так что именно делает параметр "json", если он не меняет тип содержимого на json?

Если я попробую

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

Это работает, но влияет на все мои $ .get и $ .post, которые у меня есть, и вызывает некоторые из них.

Так есть ли способ изменить поведение $ .post () для отправки contentType = application / json?

JK.
источник

Ответы:

71

Я думаю, что вам, возможно, придется

1. Измените источник, чтобы $ .post всегда использовал тип данных JSON, поскольку это просто ярлык для предварительно настроенного $.ajaxвызова.

Или

2. Определите свою собственную служебную функцию, которая является ярлыком для $.ajaxконфигурации, которую вы хотите использовать

Или

3.Вы можете перезаписать $.post functionсвою собственную реализацию с помощью патчей для обезьян.

Тип данных JSON в вашем примере относится к типу данных, возвращаемому с сервера, а не к формату, отправленному на сервер.

Русь Кэм
источник
5
+1, я бы пошел для определения нового метода или jQuery.postметода перезаписи , это действительно простая функция ...
CMS
3
Это неплохая идея, просто создайте метод с именем $ .mvcpost (), который делает то же самое, что и $ .post (путем копирования связанного кода), плюс изменяет тип содержимого. Затем для всех $ .post (), которые нужно изменить, мне просто нужно набрать 3 дополнительных символа перед собой. Это гораздо быстрее, чем переписать их как $ .ajax ().
JK.
9
@PavelRepin, мне пришлось вызвать JSON.stringify () для полезной нагрузки.
Устаман Сангат
2
@dragon - здесь есть 3 решения "есть ли способ изменить поведение $ .post () для отправки contentType = application / json?". Какая часть не является ответом?
Расс Кэм
2
Также важно знать: $ .ajax и его различные методы будут пытаться угадать, каким должен быть contentType (если он не указан), на основе данных, которые вы ему предоставляете. "mystring data"будет application/x-www-form-urlencoded;где как объект { anyKey: "anyvalue and type" }будет application/json. Многие серверы, которые читают json, допускают только объект или массив, а не строку - поэтому jquery предсказывает вещи таким образом. Если у вас есть сервер, который читает строки, числа и т. Д., Не заключая их в объект, вы должны указать тип содержимого, как в этом ответе.
bzuillsmith
395
$.ajax({
  url:url,
  type:"POST",
  data:data,
  contentType:"application/json; charset=utf-8",
  dataType:"json",
  success: function(){
    ...
  }
})

Смотрите: jQuery.ajax ()

Adrien
источник
13
Оригинальный пост спрашивает: «Так есть ли способ изменить поведение $ .post () для отправки contentType = application / json?» НО в нем также говорится: «Это работает, но влияет на все мои $ .get и $ .post, которые у меня есть, и заставляет некоторые ломаться». Я понимаю вопрос как «как я могу добиться того же, что и использование $ .post, но отправив правильный contentType, не нарушая другие вхождения $ .get и $ .post». Это неверно?
Адриен
5
@ x1a4 явно не понимает, что .ajax - это вызов, а не ajaxSetup
Уокер,
39
@ Адриен, за то, что это стоит два года спустя, твой ответ, который я искал, когда гуглил это.
AwesomeTown
74
пришлось использовать JSON.stringify(data), так как сервер ожидает, что строка JSON и jQuery просто объединят пары ключ-значение с помощью амперсандов в форме urlencoded.
дракон
3
Даже спустя четыре года этот ответ решил мои часы поиска с менее чем десятью строками кода.
Питер VDE
86

Наконец я нашел решение, которое работает для меня:

jQuery.ajax ({
    url: myurl,
    type: "POST",
    data: JSON.stringify({data:"test"}),
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function(){
        //
    }
});
vvkatwss vvkatwss
источник
8
Не могу понять, почему я продолжал получать ошибки, оказывается, что вам нужно систематизировать данные.
Заструм
5
Я знаю, что это работает, но ПОЧЕМУ? Это ошибка JQuery? Кажется, он был бы счастлив сериализовать ваш dataаргумент x-www-form-urlencoded, но если вы укажете, что тип содержимого запроса - JSON, он по-прежнему настаивает на отправке dataв несоответствующем формате.
Павел Репин
Хорошо. Я не очень много копал. Я был счастлив, что это работало. ;) Мой сервер требует JSON.
vvkatwss vvkatwss
Тоже самое. Без JSON.stringify не работает, интересно почему.
Джон Симоес
42

В итоге я добавил следующий метод в 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
    });
};

И использовать это

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

Это было сделано простым копированием кода «get» и «post» из исходных источников JQuery и жестким кодированием нескольких параметров для принудительного создания JSON POST.

Спасибо!

kontinuity
источник
2
Как обычно - лучший ответ приходит последним к партии и имеет наименьшее количество голосов; (
nikib3ro
Отличный ответ - нужно время, чтобы понять, что $ .post не делает это «из коробки».
markp3rry
21

использовать только

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

ОБНОВЛЕНО @JK: Если вы напишите в своем вопросе только один пример кода с $ .post, вы найдете один соответствующий пример в ответе. Я не хочу повторять ту же информацию, которую вы уже изучили, пока не узнали: $ .post и $ .get - это короткие формы $ .ajax. Так что просто используйте $ .ajax, и вы можете использовать полный набор его параметров без необходимости изменения каких-либо глобальных настроек.

Кстати, я бы не рекомендовал перезаписывать стандартный $ .post. Это мое личное мнение , но для меня важно не только то, что программа работает, но и то, что все, кто читает вашу программу, понимают ее одинаково. Перезапись стандартных методов без очень важной причины может привести к недоразумению при чтении программного кода. Поэтому я повторяю свою рекомендацию еще раз: просто используйте оригинальную форму $ .ajax jQuery вместо jQuery.getи, jQuery.postи вы получите программы, которые не только отлично работают, но и могут быть прочитаны людьми без каких-либо недоразумений.

Олег
источник
1
Отличное объяснение и руководство
Вед Пракаш
8

Тип данных "json", который вы можете передать в качестве последнего параметра функции post (), указывает, какой тип данных ожидает функция в ответе сервера, а не какой тип она отправляет в запросе. В частности, он устанавливает заголовок «Принять».

Честно говоря, ваш лучший выбор - переключиться на вызов ajax (). Функция post () предназначена для удобства; упрощенная версия вызова ajax () для простой публикации формы. Вы нет.

Если вы действительно не хотите переключаться, вы можете создать свою собственную функцию, скажем, xpost (), и сделать так, чтобы она просто преобразовывала заданные параметры в параметры для вызова jQuery ajax () с установленным типом содержимого. Таким образом, вместо того, чтобы переписывать все эти функции post () в функции ajax (), вам просто нужно изменить их все с post на xpost (или как угодно).

Джейкоб Маттисон
источник
Только методы $ .post (), которые вызывают метод контроллера asp.net mvc, должны быть изменены. Чистые jquery должны быть неизменными (автозаполнение, diaplog, jqgrid и т. Д.). Я надеялся, что произойдет простое изменение, которое я могу внести в соответствующие $ .post (). Но похоже, мне нужно конвертировать их в $ .ajax (). Это большое и очень тяжелое приложение, так что есть много чего изменить.
JK.
6

Это простое расширение jquery API (от: https://benjamin-schweizer.de/jquerypostjson.html ) для $ .postJSON () делает свое дело. Вы можете использовать postJSON (), как и любой другой нативный вызов jquery Ajax. Вы можете прикрепить обработчики событий и так далее.

$.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
  });
};

Как и другие API Ajax (например, $ http от AngularJS), он устанавливает правильный тип содержимого для application / json. Вы можете передавать свои данные json (объекты javascript) напрямую, так как они здесь становятся строковыми. Ожидаемый возвращенный dataType установлен в JSON. Вы можете прикрепить обработчики событий jquery по умолчанию для обещаний, например:

$.postJSON(apiURL, jsonData)
 .fail(function(res) {
   console.error(res.responseText);
 })
 .always(function() {
   console.log("FINISHED ajax post, hide the loading throbber");
 });
Рувен
источник
5

Я знаю, что это поздний ответ, у меня на самом деле есть ярлык, который я использую для публикации / чтения в / из служб на базе MS ... он работает с MVC, а также с ASMX и т. Д.

Использование:

$.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));

ПРИМЕЧАНИЕ: у меня также есть метод JSON.parseAjax, который изменен из файла JS json.org, который добавляет обработку для дат "/Date(...)/" MS ...

Измененный файл json2.js не включен, он использует синтаксический анализатор на основе сценариев в случае IE8, поскольку существуют случаи, когда собственный синтаксический анализатор прерывается при расширении прототипа массива и / или объекта и т. Д.

Я собирался обновить этот код для реализации интерфейсов обещаний, но он мне очень помог.

Tracker1
источник
4

В основе всего этого лежит тот факт, что JQuery на момент написания статьи не имеет метода postJSON, а getJSON существует и работает правильно.

метод postJSON будет делать следующее:

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

и может быть использовано так:

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
источник
1

В настоящее время документация показывает, что начиная с версии 3.0, $ .post будет принимать объект настроек, что означает, что вы можете использовать опции $ .ajax. 3.0 еще не выпущен, и в коммите, о котором они говорят, скрывают ссылку на него в документации, но ищите его в будущем!

Бен Криси
источник
1

У меня была похожая проблема со следующим кодом JavaScript:

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

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

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

Где в Fiddler я мог видеть запрос с:

  • Заголовок: Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  • Тело: {"value":"5","maxValue":"5"}

В результате мой сервер не смог сопоставить объект типу серверной части.

После изменения последней строки на эту:

$.post(url, rating, showSavedNotification);

В Скрипаче я все еще мог видеть:

  • Заголовок: Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  • Тело: value=5&maxValue=10

Однако сервер начал возвращать то, что я ожидал.

Олег Буров
источник
0

Как насчет вашего собственного адаптера / оболочки?

//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;
    }
  }
})();

И чрезвычайно простое использование:

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... }
});
затемнение
источник
Пробовал, но все еще не получил ожидаемых результатов. У меня есть Spring Boot Rest API.
Сурадж Шингейд
0

По какой-то причине установка типа контента в запросе ajax, как предложил @Adrien, в моем случае не сработала. Однако вы можете изменить тип содержимого, используя $ .post, выполнив это раньше:

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

Тогда сделайте ваш $.postзвонок:

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

У меня были проблемы с jQuery + IIS, и это было единственное решение, которое помогло jQuery понять использование кодировки windows-1252 для запросов ajax.

Johannes
источник
0

мы можем изменить Content-type следующим образом в $ .post

$ .post (url, data, function (data, status, xhr) {xhr.setRequestHeader ("Content-type", "application / x-www-form-urlencoded; charset = utf-8");});

Снзив Гупта
источник
-1

$ .post не работает, если у вас есть проблема с CORS (Cross Origin Resource Sharing). Попробуйте использовать $ .Ajax в следующем формате: "$ .ajax ({url: someurl, contentType: 'application / json', data: requestInJSONFormat, заголовки: {'Access-Control-Allow-Origin': '*'}, dataType: 'json', тип: 'POST', async: false, success: function (Data) {...}}); "

Сома Саркар
источник
-19

Вы не можете отправить application/jsonнапрямую - это должен быть параметр запроса GET / POST.

Так что-то вроде

$.post(url, {json: "...json..."}, function());
Эми Б
источник
Этот ответ может быть неправильным, но он не низкого качества, и это попытка ответить на вопрос. Из обзора .
Вай Ха Ли