Não é possível definir o tipo de conteúdo para 'application / json' em jQuery.ajax

106

Quando eu tiver este código

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

no Fiddler posso ver o seguinte pedido bruto

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

Mas o que estou tentando é definir o tipo de conteúdo de application / x-www-form-urlencoded para application / json . Mas este código

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

Gera solicitação estranha (que posso ver no 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

Por que é que? O que são OPÇÕES quando deveria haver POST lá? E onde está meu tipo de conteúdo definido como application / json? E os parâmetros de solicitação desapareceram por algum motivo.

ATUALIZAÇÃO 1

No lado do servidor, tenho um serviço RESTful muito simples.

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

Mas, por algum motivo, não posso chamar esse método com parâmetros.

ATUALIZAÇÃO 2

Desculpe por não responder tanto tempo.

Eu adicionei esses cabeçalhos à minha resposta do servidor

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

Não adiantou, tenho Método não permitido erro do servidor.

Aqui está o que meu violinista diz

insira a descrição da imagem aqui

Então, agora posso ter certeza de que meu servidor aceita POST, GET, OPTIONS (se os cabeçalhos de resposta funcionarem como eu esperava). Mas por que "Método não permitido"?

Na resposta do WebView do servidor (você pode ver a resposta bruta na imagem acima) fica assim

insira a descrição da imagem aqui

Vitalii Korsakov
fonte
2
você deve tentar o método JSON.stringfy ()
Amritpal Singh
Olhe aqui. Isso funciona muito bem para mim: stackoverflow.com/questions/9754767/…
Fanda
Estou tendo exatamente o mesmo problema, mas estou trabalhando com NodeJS como back-end, também defini todas as solicitações OPTION não apenas para serem aceitas, mas para forçar uma resposta 200 em todas as solicitações OPTION para que o restante das petições funcione conforme o esperado sem resposta ...
HeberLZ
1
Olá, @VitaliiKorsakov. resolveu seu problema? Encontro o mesmo problema, ou seja, não consigo modificar o contentType.
worldterminator
1
Eu tive o mesmo problema e acabei de fazer funcionar .. a solução está na resposta desta página: stackoverflow.com/questions/20295080/… ..para resumir: "Ao usar contentType: 'application / json' você irá não pode depender de $ _POST sendo populado. $ _POST é populado apenas para tipos de conteúdo codificados por formulário. Como tal, você precisa ler seus dados de entrada bruta de PHP ".. Vejo agora que você não está usando php no servidor lado, mas espero que esta informação ajude de alguma forma.
Sarah

Respostas:

91

Parece que remover http:// da opção url garante que o cabeçalho HTTP POST correto seja enviado.

Eu não acho que você precise qualificar totalmente o nome do host, apenas use uma URL relativa conforme abaixo.

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

Um exemplo meu 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;
        }
    });

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

Edit: Depois de mais algumas pesquisas, descobri que o cabeçalho OPTIONS é usado para descobrir se a solicitação do domínio de origem é permitida. Usando o fiddler, adicionei o seguinte aos cabeçalhos de resposta do meu servidor.

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

Depois que o navegador recebeu essa resposta, ele enviou a solicitação POST correta com dados json. Parece que o tipo de conteúdo codificado por url de formulário padrão é considerado seguro e, portanto, não passa pelas verificações extras de domínio cruzado.

Parece que você precisará adicionar os cabeçalhos mencionados anteriormente à resposta de seus servidores à solicitação OPTIONS. Obviamente, você deve configurá-los para permitir solicitações de domínios específicos, em vez de todos.

Usei o seguinte jQuery para testar isso.

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

Referências:

Mike Wade
fonte
Quero perder o acoplamento entre cliente e servidor. O servidor é um serviço RESTful e todos os clientes deste serviço devem saber o url para ele.
Vitalii Korsakov
Você pode fornecer mais alguns detalhes em seu post sobre o cenário desta questão? Se seus clientes estiverem em domínios diferentes, você poderá encontrar problemas com a mesma origem.
Mike Wade,
Publiquei informações adicionais sobre o lado do servidor. No momento, o servidor e o cliente estão no localhost, mas diferem na porta. Mais tarde, eles provavelmente estarão em domínios diferentes.
Vitalii Korsakov
Parece que o problema que você está enfrentando tem a ver com a política de mesma origem, pode valer a pena olhar para jsonp e a pergunta relacionada na minha resposta, além dessas perguntas relacionadas aos links . Guia de domínio cruzado jquery - Não tenho muita experiência com solicitações de domínio cruzado, mas espero que esses links sejam úteis para você.
Mike Wade
Eu não acho que isso seja um problema porque tudo funciona bem quando eu não passo nenhum parâmetro e o tipo de conteúdo é application / x-www-form-urlencoded. Mas não preciso da solicitação POST se não consegui passar nenhum parâmetro.
Vitalii Korsakov
41

Eu posso te mostrar como eu usei

  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
fonte
A mesma coisa que na próxima resposta. Não posso deixar de especificar o url do servidor onde todas as funções do serviço estão hospedadas
Vitalii Korsakov
@VitaliiKorsakov eu fui embora, resolva seu problema.
Amritpal Singh
Obrigado pela resposta! Eu não posso acreditar que isso não foi explicado em outro lugar. Com certeza parece que o JQuery postaria json quando o tipo que você especifica é 'json', mas acho que não ...
Jason Goemaat
1
@JasonGoemaat o parâmetro dataType em jQuery é usado apenas para analisar o corpo de resposta retornado. Se você ler a documentação, verá que nem é necessário. O valor padrão para dataType é uma estimativa inteligente. Seu problema é que o atributo de dados em jquery não é configurável. Você não pode dizer como jquery deve analisar o objeto de dados. É por isso que você precisa serializar o JSON antes. Porque jquery só serializar para url-form-encode
Loïc Faure-Lacroix
12

Portanto, tudo o que você precisa fazer para que isso funcione é adicionar:

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

como um campo para sua solicitação de postagem e funcionará.

Cody Jacques
fonte
api.jquery.com/jquery.ajax Se você olhar na documentação diz que sem especificá-lo, o padrão é 'application / x-www-form-urlencoded; charset = UTF-8 '(que é o motivo pelo qual isso está acontecendo. Mas, por que apenas definir contentType não funciona. Você pode querer verificar qual versão do jQuery você tem e atualizar se estiver em uma versão antiga).
Cody Jacques
Isto não está a funcionar. Mesmo que eu tenha type: "POST", ele está enviando OPTIONS.
user9645 de
5

Eu reconheci essas telas, estou usando CodeFluentEntities e tenho uma solução que funcionou para mim também.

Estou usando essa construção:

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

como você pode ver, se eu usar

contentType: "",

ou

contentType: "text/plain", //chrome

Tudo funciona bem.

Não estou 100% certo de que é tudo de que você precisa, porque também alterei os cabeçalhos.

Alexey Avdeyev
fonte
5

Se você usar este:

contentType: "application/json"

AJAX não enviará parâmetros GET ou POST para o servidor ... não sei por quê.

Levei horas para aprender hoje.

Apenas use:

$.ajax(
  { url : 'http://blabla.com/wsGetReport.php',
    data : myFormData, type : 'POST', dataType : 'json', 
    // contentType: "application/json", 
    success : function(wsQuery) { }
  }
)
Luis Arturo Erique Guajala
fonte
1
infelizmente a resposta correta para mim. Omita contentType e apenas use dataType para ignorar o lixo de OPÇÕES do CORS que muitos serviços simplesmente não implementam corretamente. Tão irritante.
Umopepisdn
2

Eu encontrei a solução para este problema aqui . Não se esqueça de permitir o verbo OPTIONS no manipulador de serviço de aplicativo IIS.

Funciona bem. Obrigado André Pedroso. :-)

Fanda
fonte
1

Eu tive o mesmo problema. Estou executando um aplicativo java rest em um servidor jboss. Mas acho que a solução é semelhante em um webapp ASP .NET.

O Firefox faz uma pré-chamada para o seu servidor / URL restante para verificar quais opções são permitidas. Essa é a solicitação "OPÇÕES" à qual seu servidor não responde de acordo. Se esta chamada OPTIONS for respondida corretamente, uma segunda chamada é realizada, que é a solicitação "POST" real com conteúdo json.

Isso só acontece ao realizar uma chamada entre domínios. No seu caso, chamar ' http://localhost:16329/Hello' em vez de chamar um caminho de url no mesmo domínio '/ Hello'

Se você pretende fazer uma chamada de domínio cruzado, você precisa aprimorar sua classe de serviço restante com um método anotado que suporta uma solicitação http "OPÇÕES". Esta é a implementação java de acordo:

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

Então eu acho que no .NET você tem que adicionar um método adicional anotado com

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

onde os seguintes cabeçalhos são definidos

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

Consegui a solução para enviar os dados JSON por solicitação POST através do jquery ajax. Usei o código abaixo

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


        });
    });

Eu usei 'Content-Type': 'text/plain'no cabeçalho para enviar os dados json brutos.
Porque se usarmos Content-Type: 'application/json'os métodos de solicitação convertidos em OPÇÃO, mas usando Content-Type: 'test/plain'o método não é convertido e permanece como POST. Espero que isso ajude alguém.

Rahul Aparajit
fonte
3
Na verdade, ele não está convertendo para OPTION, mas sim enviando uma solicitação de simulação do CORS para verificar se o POST é permitido. Quando isso não dá certo, o POST não acontece.
Umopepisdn
0

Oi, essas duas linhas funcionaram para mim.

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

Obrigado, Prashant

Prashant Kumar
fonte