XMLHttpRequest status 0 (responseText está vazio)

104

Não é possível obter dados com XMLHttpRequest (status 0 e responseText está vazio):

xmlhttp = new XMLHttpRequest ();
xmlhttp.open ("GET", "http://www.w3schools.com/XML/cd_catalog.xml", true);
xmlhttp.onreadystatechange = function () 
{
  if (xmlhttp.readyState == 4)
    alert ("status" + xmlhttp.status);
}
xmlhttp.send ();

Alerta "status 0".

A mesma situação com a solicitação localhost (cd_catalog.xml é salvo como um arquivo local)

xmlhttp.open ("GET", "http: //localhost/cd_catalog.xml", true);

Mas com a solicitação de IP localhost

xmlhttp.open ("GET", "http://127.0.0.1/cd_catalog.xml", verdadeiro);

e com a solicitação de arquivo local

xmlhttp.open ("GET", "cd_catalog.xml", true);

está tudo bem (status 200)

O que pode causar o problema (status = 0) com a solicitação online?

PS: Live HTTP Headers mostra que tudo está OK em todos os 4 casos:

  HTTP / 1.1 200 OK
  Comprimento do conteúdo: 4742

PS2: servidor da web local Apache em VMWare (sistema operacional Win7, sistema operacional Ubuntu, adaptador de rede - NAT). Navegador - Firefox.

Arigasa
fonte
1
É a sua página de teste http://127.0.0.1por acaso? ;)
Roatin Marth de
Sim. <code> 127.0.0.1/CDCatalogTest.html </code>
arigasa
7
Você respondeu sua pergunta. XMLHttpRequestnão pode fazer solicitações entre domínios. Existem algumas soluções alternativas. Veja jquery, por exemplo.
meze de
Use php para obter o arquivo. Pequena solução alternativa
2
@meze: Chamadas entre domínios funcionam com jQuery. Mas como isso pode não funcionar com JavaScript simples, já que jQuery é implementado em JavaScript? Isso não faz sentido para mim. O jQuery está usando algum tipo de solução alternativa desagradável?
Gruber

Respostas:

55

status é 0 quando seu arquivo html contendo o script é aberto no navegador por meio do esquema de arquivo. Certifique-se de colocar os arquivos em seu servidor (apache ou tomcat qualquer) e depois abri-lo via protocolo http no navegador. (ou seja, http: //localhost/myfile.html ) Esta é a solução.

Abhishek_8
fonte
1
Por que isso está sendo rejeitado? É verdade! Solicitações XHR de arquivo: // URLs de arquivos também no arquivo: // URLs realmente têm status == 0 em caso de sucesso (testado em FF 24.0.5).
Daniel Roethlisberger
3
Também estou obtendo status == 0 em caso de sucesso no Safari versão 6.1.6.
Planar
Estou tendo status = 0 (mas status 200 na rede) usando Carregar complemento temporário no firefox
JobaDiniz
1
ainda resposta válida. A resposta HTTP é 200 para esquemas remotos reais (http et al.) E 0 para arquivo local ( file://esquema). Obviamente, você precisa primeiro permitir o carregamento local do arquivo desabilitando o CORS.
pid
31

A causa de seus problemas é que você está tentando fazer uma chamada entre domínios e ela falha .

Se você estiver fazendo o desenvolvimento localhost, poderá fazer chamadas entre domínios - eu faço isso o tempo todo.

Para Firefox, você deve habilitá-lo em suas configurações

signed.applets.codebase_principal_support = true

Em seguida, adicione algo assim ao seu código aberto XHR:

  if (isLocalHost()){
    if (typeof(netscape) != 'undefined' && typeof(netscape.security) != 'undefined'){
      netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead');
    }
  }

Para o IE, se bem me lembro, tudo que você precisa fazer é habilitar a configuração de Segurança do navegador em "Diversos → Acessar fontes de dados entre domínios" para fazê-lo funcionar com ActiveX XHRs.

O IE8 e superior também adicionaram recursos de domínio cruzado aos objetos XmlHttpRequest nativos, mas ainda não brinquei com eles.

Que bate com violência
fonte
8
Caso alguém precise, para o Chrome você precisa iniciar uma nova instância dele (sem nenhuma já aberta) e usar--allow-file-access-from-files
TheZ
@TheZ: Você está 100%? Ouvi dizer que você só precisa executar uma nova instância do Chrome, com --allow-file-access-from-filesswitch, mas não precisa fechar todas as outras instâncias em execução. Exatamente como no caso do Modo Incógnito do Chrome - você pode usá-lo, sem fechar nenhuma outra instância em execução.
trejder
Parece que o suporte para 'UniversalBrowserRead' foi eliminado, portanto, essa solução alternativa não é uma opção.
perilandmishap
Além disso, isso pode acontecer quando você solicita uma página http da página https (como uma extensão no navegador).
sibvic
Estou encontrando este problema, apesar da página html e do script AJAX residirem no mesmo domínio. Mas, estranhamente, está afetando apenas alguns scripts, principalmente os scripts que acessam os recursos do MongoDB. Alguma pista do porquê disso?
David Edwards de
26

Na verdade, certifique-se de que o tipo de botão é Botão não enviar, que causou conflito de status onde me encontrei recentemente.

dyuan
fonte
1
Há um conflito porque o envio de um formulário tem algum comportamento padrão que você precisa evitar se estiver lidando com o evento e fazendo uma chamada ajax. Você pode evitar o comportamento padrão pegando o evento em seu manipulador e chamandoe.preventDefault()
Jordan
20

Se o servidor responder a um método OPTIONS e a GET e POST (qualquer um deles) com um cabeçalho como:

Access-Control-Allow-Origin: *

Pode funcionar bem. Parece no FireFox 3.5 e rekonq 0.4.0. Aparentemente, com esse cabeçalho e a resposta inicial a OPÇÕES, o servidor está dizendo ao navegador: "Vá em frente e deixe essa solicitação entre domínios passar."

Alex Robinson
fonte
3
Esta é a resposta certa! Veja en.wikipedia.org/wiki/Cross-origin_resource_sharing para mais informações. Se você adicionar este cabeçalho, não será 'pode funcionar', mas 'funcionará'. NB O que você precisa adicionar é um HTTP / resposta / cabeçalho - então você só pode fazer isso em um servidor que você controla. Nunca será possível buscar diretamente w3schools.com/XML/cd_catalog.xml usando XMLHttpRequest(ou seja, de acordo com a pergunta original), porque esse recurso não inclui (pelo menos em 24 de abril de 2015) qualquer cabeçalho CORS.
MikeBeaton
13

Considere também o tempo limite da solicitação :

O navegador moderno retorna readyState = 4 e s tatus = 0 se muito tempo passa antes da resposta do servidor.

Andrea Savojardo
fonte
3
@AndreaSavojardo: Você tem alguma referência (como uma postagem no MDN) sobre se esse comportamento está em conformidade com os padrões?
Alexander Abakumov
@AndreaSavojardo Eu tenho readyState = 4 e status = 0 e o servidor não está rodando, mas o alerta de erro é mostrado rapidamente .... quanto tempo passa para "solicitar tempo limite"?
7

Adicione setRequestHeader("Access-Control-Allow-Origin","*")à sua resposta do servidor.

Ivan
fonte
3

Eu havia enfrentado um problema semelhante. Tudo estava bem, o "readystate" era 4, mas o "status" era 0. Era porque eu estava usando um servidor portátil Apache PHP e meu arquivo no qual usei o objeto "XMLHttpRequest" era um arquivo html. Mudei a extensão do arquivo para php e o problema foi resolvido.

Reyan
fonte
3

Abra o console javascript . Você verá uma mensagem de erro lá. No meu caso, foi CORS.

Jarekczek
fonte
2

Para responder à pergunta de por que http://127.0.0.1/cd_catalog.xmlfunciona enquanto http://localhost/cd_catalog.xmlnão funciona : o Firefox está tratando 127.0.0.1 e localhost como dois domínios diferentes.

Tomi Aarnio
fonte
2

Para ver qual é o problema, quando você obtiver o erro críptico 0, vá para ... | Mais ferramentas | Ferramentas do desenvolvedor (Ctrl + Shift + I) no Chrome (na página que apresenta o erro)

Leia o texto em vermelho no log para obter a mensagem de erro verdadeira. Se houver muitos itens lá, clique com o botão direito e apague o console e, em seguida, faça sua última solicitação novamente.

Meu primeiro problema foi que eu estava passando cabeçalhos de autorização para meu próprio serviço da web de domínio cruzado para o navegador pela primeira vez.

Eu já tive:

Access-Control-Allow-Origin: *

Mas não:

Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization

no cabeçalho de resposta do meu serviço da web.

Depois de adicionar isso, meu erro zero tinha desaparecido do meu próprio servidor web, bem como ao executar o arquivo index.html localmente sem um servidor web, mas ainda estava dando erros na caneta de código.

Voltar para ... | Mais ferramentas | Ferramentas do desenvolvedor ao obter o erro no codepen, e aí está claramente explicado: codepen usa https, então não posso fazer chamadas para http, pois a segurança é menor.

Portanto, preciso hospedar meu serviço da web em https.

Saber como obter a verdadeira mensagem de erro - não tem preço!

Maia
fonte
Usei essa abordagem (f12 no Chrome) e descobri que estava tentando ir de https para http, que estava falhando silenciosamente, sem fornecer nada de útil. MENSAGEM DE ERRO: VM1152: 1 Conteúdo misto: A página em 'https://mysiteoriginsite' foi carregada por HTTPS, mas solicitou um ponto de extremidade XMLHttpRequest inseguro 'http://MyDestinationSite/MyService.svc'. Esta solicitação foi bloqueada; o conteúdo deve ser servido por HTTPS.
GrayDwarf
1

Aqui está outro caso em que status === 0 , específico para upload:

Se você anexar um 'load'manipulador de eventos a XHR.upload, conforme sugerido pelo MDN (role para baixo até a parte de upload de 'Monitorando o progresso'), o objeto XHR terá status=0e todas as outras propriedades serão strings vazias. Se você anexar o'load' manipulador diretamente ao objeto XHR, como faria ao baixar o conteúdo, não terá problemas (visto que não está executando fora do localhost).

No entanto, se você deseja obter dados 'progress'confiáveis em seus manipuladores de eventos, é necessário anexar um manipulador a XHR.upload, não diretamente, ao próprio objeto XHR.

Eu só testei isso até agora no Chrome OSX, então não tenho certeza de quanto do problema aqui é a documentação do MDN e quanto é a implementação do Chrome ...

Ericsoco
fonte
1

Alex Robinson já (e primeiro) dá a resposta correta para esta questão. Mas para elaborar um pouco mais ...

Você deve adicionar o cabeçalho de resposta HTTP:

Access-Control-Allow-Origin: *

Se você fizer isso, o resultado não será apenas 'pode funcionar', mas 'funcionará'.

NB O que você precisa adicionar é um cabeçalho de resposta HTTP - então você só pode fazer isso em um servidor que você controla. Nunca será possível buscar diretamente http://w3schools.com/XML/cd_catalog.xml de seu URL original usando um XMLHttpRequest(de acordo com a pergunta de OP), porque esse recurso não (pelo menos, não em 24 de abril de 2015) inclua qualquer cabeçalho CORS.

http://en.wikipedia.org/wiki/Cross-origin_resource_sharing fornece mais informações.

MikeBeaton
fonte
0

Meu problema semelhante a este foi resolvido verificando meu código html. Eu estava tendo um onclickmanipulador em meu botão de envio de formulário para um método. assim: onclick="sendFalconRequestWithHeaders()". Este método, por sua vez, chama ajax exatamente como o seu e faz o que eu quero. Mas não como esperado, meu navegador não estava retornando nada.

Aprendido com o trabalho duro de alguém , retornei falso neste manipulador e resolvi. Deixe-me mencionar que antes de chegar a este post, eu passei 3 dias de fim de semana inteiro e uma de meio dia em código escritório escrita implementar CORS filters, jetty config, outras jersey and embedded jettycoisas relacionadas - apenas para corrigir isso, revolvendo todo o meu redor entendimento.cross domain ajax requests E coisas padrões. Era ridículo como erros simples em javascript deixam você burro.

Para ser verdade, tentei signed.applets.codebase_principal_support = truee escrevi isLocalHost() **if**. pode ser que este método precise ser implementado por nós, o firefox diz que não existe. Agora eu tenho que limpar meu código para enviar o patch git de forma limpa. Graças a esse alguém.

Siva Tumma
fonte
0

Uma solicitação de navegador "127.0.0.1/somefile.html" chega inalterada ao servidor da web local, enquanto "localhost / somefile.html" pode chegar como "0: 0: 0: 0: 0: 0: 0: 1 / somefile.html "se IPv6 for compatível. Portanto, o último pode ser processado como indo de um domínio para outro.

Massimo roscio
fonte
0

Alex Robinson e bmju forneceram informações valiosas para entender os problemas de origem cruzada. Gostaria de acrescentar que pode ser necessário fazer uma chamada OPTIONS explícita em seu código de cliente antes de fazer o GET / POST desejado (por exemplo, em um terminal de serviço CORS OAuth). Seu navegador / biblioteca pode não processar automaticamente a solicitação OPTIONS. Gruber, esta é uma das respostas possíveis à sua pergunta.

Tim McConnell
fonte
0

Eu tive o mesmo problema (readyState era 4 e status 0) , então segui uma abordagem diferente explicada neste tutorial: https://spring.io/guides/gs/consuming-rest-jquery/

Ele não usou XMLHttpRequest , em vez disso, usou o método jquery $ .ajax () :

<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="hello.js"></script>
</head>

<body>
    <div>
        <p class="greeting-id">The ID is </p>
        <p class="greeting-content">The content is </p>
    </div>
</body>

e para o arquivo public / hello.js (ou você pode inseri-lo diretamente no mesmo código HTML):

$(document).ready(function() 
 {
    $.ajax({
        url: "http://rest-service.guides.spring.io/greeting"
   }).then(function(data) {
      $('.greeting-id').append(data.id);
      $('.greeting-content').append(data.content);
   });
 });
RMDev
fonte
2
Você sabe que jQuery $.ajax()usa XMLHttpRequestpor dentro, não é?
Manngo,
-1

Eu só tive esse problema porque usei 0.0.0.0como meu servidor, mudei para localhoste ele funciona.

Vad
fonte
-4

Editar: Por favor, leia os comentários de Malvolio abaixo, pois o conhecimento desta resposta está desatualizado.

Você não pode fazer XMLHttpRequests de domínio cruzado.

A chamada 127.0.0.1funciona porque sua página de teste está localizada em127.0.0.1 , e o teste local também funciona porque, bem ... é um teste local.

Os outros dois testes falham porque o JavaScript não pode se comunicar com um servidor distante por meio de XMLHttpRequest.

Em vez disso, você pode considerar:

  • XMLHttp-solicite seu próprio servidor para buscar seu conteúdo XML remoto para você (script php, por exemplo)
  • Tentando usar um serviço como GoogleAppEngine se quiser mantê-lo em JavaScript completo.

espero que ajude

Gabriel Sprenger
fonte
40
Isso é simplesmente errado. Você pode fazer XMLHttpRequests entre domínios.
Malvolio
1
"Você não pode" como em "Você não deve fazer isso porque nunca é uma boa ideia"
Gabriel Sprenger
24
- justo, mas não sei se um comentário é o melhor fórum para isso. XMLHttpRequests entre domínios certamente apresentam alguns desafios de segurança, mas oferecem todas as ferramentas necessárias para lidar com esses desafios. Além disso, eles permitem que os sites ofereçam serviços facilmente a outros sites, usem CDNs para propagar dados e respondam mais rapidamente às solicitações dos usuários. Se você tiver alguma dúvida específica, pode me enviar uma mensagem, ou melhor, postar uma pergunta aqui no SO e chamar minha atenção para ela.
Malvolio
2
@GabrielSprenger: Cross-domain XMLHttpRequests não é apenas uma boa ideia, é tão comum hoje em dia que NÃO fazê-los em um aplicativo da web moderno (além de algum tipo de HelloWorlds) é algo ridículo. Qualquer serviço REST externo que seu aplicativo consome requer um domínio cruzado XMLHttpRequest. E é por isso que todo esse material CORS foi adicionado.
Alexander Abakumov