No se puede establecer el tipo de contenido en 'application / json' en jQuery.ajax

106

Cuando tengo este código

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

en Fiddler puedo ver la siguiente solicitud sin procesar

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

Pero lo que estoy intentando es establecer el tipo de contenido de application / x-www-form-urlencoded a application / json . Pero este codigo

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

Genera una solicitud extraña (que puedo ver en Fiddler)

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

¿Porqué es eso? ¿Cuáles son las OPCIONES cuando debería ser POST allí? ¿Y dónde está mi tipo de contenido establecido en application / json? Y los parámetros de solicitud se han ido por alguna razón.

ACTUALIZACIÓN 1

En el lado del servidor, tengo un servicio RESTful realmente simple.

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

Pero por alguna razón no puedo llamar a este método con parámetros.

ACTUALIZACIÓN 2

Perdón por no responder tanto tiempo.

Agregué estos encabezados a la respuesta de mi servidor

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

No ayudó, tengo un error de Método no permitido del servidor.

Esto es lo que dice mi violinista

ingrese la descripción de la imagen aquí

Entonces, ahora puedo estar seguro de que mi servidor acepta POST, GET, OPTIONS (si los encabezados de respuesta funcionan como espero). Pero, ¿por qué "Método no permitido"?

En la respuesta de WebView del servidor (puede ver la respuesta sin procesar en la imagen de arriba) se ve así

ingrese la descripción de la imagen aquí

Vitalii Korsakov
fuente
2
debería probar el método JSON.stringfy ()
Amritpal Singh
Mira aquí. Esto me funciona muy bien: stackoverflow.com/questions/9754767/…
Fanda
Tengo exactamente el mismo problema, pero estoy trabajando con NodeJS como backend, también configuré todas las solicitudes de OPCIÓN no solo para que sean aceptadas sino para forzar una respuesta de 200 en todas las solicitudes de OPCIÓN para que el resto de las solicitudes funcionen como se esperaba sin respuesta ...
HeberLZ
1
Hola @VitaliiKorsakov. ¿Has resuelto tu problema? Me encuentro con el mismo problema, es decir, no puedo modificar contentType.
worldterminator
1
Tuve el mismo problema y lo hice funcionar ... la solución está en la respuesta en esta página: stackoverflow.com/questions/20295080/… .. para resumir: "Cuando use contentType: 'application / json' no puede confiar en que se rellene $ _POST. $ _POST solo se rellena para tipos de contenido codificados por formulario. Como tal, debe leer sus datos desde la entrada sin procesar de PHP ". Veo que ahora no está usando php en el servidor lado, pero espero que esta información ayude de alguna manera.
Sarah

Respuestas:

91

Parecería que eliminar http://de la opción de URL garantiza que se envíe el encabezado HTTP POST correcto.

No creo que necesite calificar completamente el nombre del host, solo use una URL relativa como se muestra a continuación.

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

Un ejemplo mío que funciona:

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

Posiblemente relacionado: jQuery $ .ajax (), $ .post enviando "OPTIONS" como REQUEST_METHOD en Firefox

Editar: Después de investigar un poco más, descubrí que el encabezado OPTIONS se usa para averiguar si la solicitud del dominio de origen está permitida. Usando Fiddler, agregué lo siguiente a los encabezados de respuesta de mi servidor.

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

Una vez que el navegador recibió esta respuesta, envió la solicitud POST correcta con datos json. Parecería que el tipo de contenido con código de URL de formulario predeterminado se considera seguro y, por lo tanto, no se somete a las comprobaciones adicionales entre dominios.

Parece que deberá agregar los encabezados mencionados anteriormente a la respuesta de su servidor a la solicitud de OPCIONES. Por supuesto, debe configurarlos para permitir solicitudes de dominios específicos en lugar de todos.

Usé el siguiente jQuery para probar esto.

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

Referencias:

Mike Wade
fuente
Quiero perder el acoplamiento entre cliente y servidor. El servidor es un servicio RESTful y todos los clientes de este servicio deben conocer la URL correspondiente.
Vitalii Korsakov
¿Puede proporcionar algunos detalles más en su publicación sobre el escenario de esta pregunta? Si sus clientes van a estar en dominios diferentes, es posible que encuentre problemas con el mismo origen.
Mike Wade
He publicado información adicional sobre el lado del servidor. En este momento, el servidor y el cliente están en localhost pero difieren en el puerto. Más adelante, lo más probable es que estén en dominios diferentes.
Vitalii Korsakov
Parece que el problema que está experimentando tiene que ver con la misma política de origen, podría valer la pena mirar jsonp y la pregunta a la que me vinculé en mi respuesta, además de estas preguntas relacionadas con los enlaces . Guía de dominios cruzados de jquery : no tengo mucha experiencia con solicitudes de dominios cruzados, pero espero que esos enlaces te sean de utilidad.
Mike Wade
No creo que esto sea un problema porque todo funciona bien cuando no paso ningún parámetro y el tipo de contenido es application / x-www-form-urlencoded. Pero no necesito una solicitud POST si no pude pasar ningún parámetro.
Vitalii Korsakov
41

Puedo mostrarte como lo usé

  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
fuente
Lo mismo que en la siguiente respuesta. No puedo no especificar la URL del servidor donde se alojan todas las funciones del servicio
Vitalii Korsakov
@VitaliiKorsakov me fui, ¿has resuelto tu problema?
Amritpal Singh
¡Gracias por la respuesta! No puedo creer que esto no esté escrito en otra parte. Seguro que parece que JQuery publicaría json cuando el tipo que especificas es 'json', pero supongo que no ...
Jason Goemaat
1
@JasonGoemaat el parámetro dataType en jQuery solo se usa para analizar el cuerpo de respuesta devuelto. Si lee la documentación, verá que ni siquiera es necesaria. El valor predeterminado para dataType es conjetura inteligente. Su problema es que el atributo de datos en jquery no es configurable. No se puede decir cómo jquery debe analizar el objeto de datos. Por eso tienes que serializar json antes. Porque jquery solo se serializa en url-form-encode
Loïc Faure-Lacroix
12

Entonces, todo lo que necesita hacer para que esto funcione es agregar:

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

como un campo para su solicitud de publicación y funcionará.

Cody Jacques
fuente
api.jquery.com/jquery.ajax Si miras en la documentación, dice que sin especificarlo por defecto es 'application / x-www-form-urlencoded; charset = UTF-8 '(que es la razón por la que está sucediendo. Idk por qué simplemente configurar contentType no funciona. Es posible que desee verificar qué versión de jQuery tiene y actualizar si está en una versión anterior).
Cody Jacques
Esto no está funcionando. Aunque tengo type: "POST", está enviando OPTIONS.
user9645
5

Reconocí esas pantallas, estoy usando CodeFluentEntities y tengo una solución que también funcionó para mí.

Estoy usando esa construcción:

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

como puedes ver, si uso

contentType: "",

o

contentType: "text/plain", //chrome

Todo funciona bien.

No estoy 100% seguro de que sea todo lo que necesitas, porque también he cambiado los encabezados.

Alexey Avdeyev
fuente
5

Si usa esto:

contentType: "application/json"

AJAX no enviará parámetros GET o POST al servidor ... no sé por qué.

Me tomó horas aprenderlo hoy.

Solo usa:

$.ajax(
  { url : 'http://blabla.com/wsGetReport.php',
    data : myFormData, type : 'POST', dataType : 'json', 
    // contentType: "application/json", 
    success : function(wsQuery) { }
  }
)
Luis Arturo Erique Guajala
fuente
1
lamentablemente la respuesta correcta para mí. Omita contentType y simplemente use dataType para omitir la basura CORS OPTIONS que muchos servicios simplemente no implementan correctamente. Muy molesto.
Umopepisdn
2

Encontré la solución para este problema aquí . No olvide permitir OPCIONES de verbo en el controlador de servicio de la aplicación IIS.

Funciona bien. Gracias André Pedroso. :-)

Fanda
fuente
1

Tuve el mismo problema. Estoy ejecutando una aplicación Java rest en un servidor jboss. Pero creo que la solución es similar en una aplicación web ASP .NET.

Firefox realiza una llamada previa a su servidor / URL de descanso para verificar qué opciones están permitidas. Esa es la solicitud de "OPCIONES" a la que su servidor no responde en consecuencia. Si esta llamada de OPCIONES se responde correctamente, se realiza una segunda llamada, que es la solicitud "POST" real con contenido json.

Esto solo ocurre cuando se realiza una llamada entre dominios. En su caso, llamar a ' http://localhost:16329/Hello' en lugar de llamar a una ruta de URL bajo el mismo dominio '/ Hello'

Si tiene la intención de realizar una llamada entre dominios, debe mejorar su clase de servicio de descanso con un método anotado que admite una solicitud http "OPCIONES". Esta es la implementación de Java correspondiente:

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

Así que supongo que en .NET debe agregar un método adicional anotado con

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

donde se establecen los siguientes encabezados

.header("Access-Control-Allow-Origin", "*")
        .header("Access-Control-Allow-Headers", "Content-Type")
        .header("Access-Control-Allow-Methods", "POST, OPTIONS")
Vincent
fuente
0

Obtuve la solución para enviar los datos JSON por solicitud POST a través de jquery ajax. Usé el siguiente código

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


        });
    });

Usé 'Content-Type': 'text/plain'en el encabezado para enviar los datos json sin procesar.
Porque si usamos Content-Type: 'application/json'los métodos de solicitud convertidos a OPCIÓN, pero usando Content-Type: 'test/plain'el método no se convierte y permanece como POST. Espero que esto ayude a alguien.

Rahul Aparajit
fuente
3
Realmente no se está convirtiendo a OPCIÓN, está enviando una solicitud de verificación previa CORS para verificar si se permite la publicación POST. Cuando esto no vuelve bien, el POST no sucede.
Umopepisdn
0

Hola, estas dos líneas funcionaron para mí.

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

Gracias, Prashant

Prashant Kumar
fuente