Por que o Postman não obtém um erro "Nenhum cabeçalho 'Acesso-controle-permissão-origem' está presente no recurso solicitado" quando meu código JavaScript é exibido?

2503

Nota da modificação : Esta pergunta é sobre por que o Postman não está sujeito a restrições de CORS da mesma maneira que um XMLHttpRequest. Esta pergunta não é sobre como corrigir um erro "Não 'Acesso ao controle de permissão de origem' ...".

Pare de postar :


Estou tentando fazer autorização usando JavaScript , conectando -me ao Flask interno da API RESTful . No entanto, quando faço a solicitação, recebo o seguinte erro:

XMLHttpRequest não pode carregar http: // myApiUrl / login . Nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Portanto, a origem 'null' não é permitida.

Sei que a API ou o recurso remoto deve definir o cabeçalho, mas por que funcionou quando fiz a solicitação pela extensão Postman do Chrome ?

Este é o código da solicitação:

$.ajax({
    type: "POST",
    dataType: 'text',
    url: api,
    username: 'user',
    password: 'pass',
    crossDomain : true,
    xhrFields: {
        withCredentials: true
    }
})
    .done(function( data ) {
        console.log("done");
    })
    .fail( function(xhr, textStatus, errorThrown) {
        alert(xhr.responseText);
        alert(textStatus);
    });
Mr Jedi
fonte
32
Você está fazendo a solicitação do host local ou executando diretamente o HTML?
MD. Sahib Bin Mahboob
@ MD.SahibBinMahboob Se entendi sua pergunta, solicito ao localhost - tenho uma página no meu computador e apenas a executo. Quando implanto site na hospedagem, ele dá o mesmo resultado.
Sr. Jedi
6
muito relacionado: stackoverflow.com/questions/10143093/…
cregox
8
Para quem procura mais leitura, MDN tem um bom artigo tudo sobre ajax e solicitações de origem cruzada: developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Sam Eaton
1
Uma observação importante para esse tipo de erro no nó js. Você DEVE definir seus cabeçalhos de acesso na inicialização do seu arquivo server.js ANTES de começar a configurar suas rotas. Caso contrário, tudo correrá muito bem, mas você receberá esse erro ao fazer solicitações do seu aplicativo.
Alex J

Respostas:

1346

Se eu entendi direito, você está fazendo um XMLHttpRequest em um domínio diferente do que sua página está. Portanto, o navegador está bloqueando-o, pois normalmente permite uma solicitação na mesma origem por motivos de segurança. Você precisa fazer algo diferente quando quiser fazer uma solicitação entre domínios. Um tutorial sobre como conseguir isso é Usando o CORS .

Quando você está usando carteiro, eles não são restritos por esta política. Citado em XMLHttpRequest de origem cruzada :

As páginas da Web regulares podem usar o objeto XMLHttpRequest para enviar e receber dados de servidores remotos, mas são limitadas pela mesma política de origem. As extensões não são tão limitadas. Uma extensão pode conversar com servidores remotos fora de sua origem, desde que solicite primeiro permissões de origem.

MD. Sahib Bin Mahboob
fonte
7
Você está certo. Estou fazendo uma solicitação para um domínio diferente da minha página. A API está no servidor e eu executo a solicitação do localhost. Antes de aceitar a resposta, você pode me explicar o que significa "executar a solicitação diretamente"? POSTMAN não usa domínio?
Sr. Jedi
181
O navegador não está bloqueando a solicitação. Os únicos navegadores que bloqueiam completamente solicitações de ajax de origem cruzada são o IE7 ou mais antigo. Todos os navegadores, com exceção do IE7 e anteriores, implementam a especificação CORS (IE8 e IE9 parcialmente). Tudo que você precisa fazer é aceitar solicitações CORS no servidor de API retornando os cabeçalhos adequados com base na solicitação. Você deve ler os conceitos do CORS em mzl.la/VOFrSz . O Postman também envia solicitações via XHR. Se você não encontrar o mesmo problema ao usar o carteiro, isso significa que você não está enviando a mesma solicitação via carteiro.
Raio Nicholus
10
@ MD.SahibBinMahboob O Postman NÃO está enviando uma solicitação "do seu código java / python". Está enviando a solicitação diretamente do navegador. O XHR nas extensões do Chrome funciona de maneira um pouco diferente, especialmente quando há solicitações de origem cruzada .
Raio Nicholus
250

AVISO: O uso Access-Control-Allow-Origin: *pode tornar sua API / site vulnerável a ataques de falsificação de solicitação entre sites (CSRF). Certifique-se de entender os riscos antes de usar este código.

É muito simples de resolver se você estiver usando PHP . Basta adicionar o seguinte script no início da sua página PHP que lida com a solicitação:

<?php header('Access-Control-Allow-Origin: *'); ?>

Se você estiver usando o Node-red, precisará permitir o CORS no node-red/settings.jsarquivo, sem comentar as seguintes linhas:

// The following property can be used to configure cross-origin resource sharing
// in the HTTP nodes.
// See https://github.com/troygoode/node-cors#configuration-options for
// details on its contents. The following is a basic permissive set of options:
httpNodeCors: {
 origin: "*",
 methods: "GET,PUT,POST,DELETE"
},

Se você estiver usando o Flask da mesma forma que a pergunta; você tem que instalar primeiroflask-cors

$ pip install -U flask-cors

Em seguida, inclua os Flask cors em seu aplicativo.

from flask_cors import CORS

Uma aplicação simples será semelhante a:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
  return "Hello, cross-origin-world!"

Para mais detalhes, você pode verificar a documentação do Flask .

Shady Sherif
fonte
93
e não é seguro
llazzaro
153
Você não deve desativar o CORS porque não sabe para que serve. Esta é uma resposta terrível.
meagar
124
Mesmo que não seja seguro, a questão não era sobre segurança, mas como realizar a tarefa. Essa é uma das opções que um desenvolvedor deve escolher ao lidar com solicitações AJAX entre domínios. Isso me ajudou a resolver o problema e, para meu aplicativo, não me importo de onde os dados vieram. Eu desinfecto toda a entrada com PHP no domínio de destino, portanto, se alguém quiser postar algum lixo nele, deixe-os tentar. O ponto principal aqui é que o AJAX entre domínios pode ser permitido no domínio de destino. +1 para a resposta.
ZurabWeb
23
Embora eu concorde com a mensagem geral de Piero, não se trata especificamente de segurança, mas a segurança é uma preocupação. Eu acho que isso deveria ter pelo menos dito algo como "Isso geralmente é ruim! Não faça isso a menos que você saiba o que está fazendo! Aqui está mais documentação: ..." e talvez explique brevemente o porquê. Eu odiaria que alguém viesse aqui e pensasse "Oh, eu posso apenas adicionar / ajustar esse cabeçalho e estou bem!" e não conhecer todas as ramificações. Quero dizer, é meio que eles pesquisem e tudo, mas ainda assim.
Thomas F.
4
Eu gosto desta resposta ... Tenho o mesmo problema e resolve-o ... Ele explicou que existem alguns problemas de segurança, mas esse é outro problema e permite que todos pensem e resolvam esse problema individualmente ...
Ari Waisberg
64

Porque
$ .ajax ({type: "POST" - chama OPTIONS
$ .post ( - chama POST

Ambos são diferentes. O carteiro chama "POST" corretamente, mas quando o chamamos, será "OPTIONS".

Para serviços web C # - API Web

Por favor, adicione o seguinte código no seu arquivo web.config na tag <system.webServer>. Isso funcionará:

<httpProtocol>
    <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
    </customHeaders>
</httpProtocol>

Verifique se você não está cometendo nenhum erro na chamada do Ajax

jQuery

$.ajax({
    url: 'http://mysite.microsoft.sample.xyz.com/api/mycall',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    type: "POST", /* or type:"GET" or type:"PUT" */
    dataType: "json",
    data: {
    },
    success: function (result) {
        console.log(result);
    },
    error: function () {
        console.log("error");
    }
});

Nota: Se você estiver procurando por baixar conteúdo de um site de terceiros , isso não ajudará . Você pode tentar o seguinte código, mas não o JavaScript.

System.Net.WebClient wc = new System.Net.WebClient();
string str = wc.DownloadString("http://mysite.microsoft.sample.xyz.com/api/mycall");
George Livingston
fonte
Essa configuração resolveu o mesmo erro no Wordpress nos Serviços do Azure. Obrigado.
Andre Mesquita
9
Sugiro usar um valor de origem específico para evitar solicitações de domínios externos. Assim, por exemplo, em vez de *usohttps://www.myotherdomain.com
Pechar
O link hubfly.com/blog/solutions/how-to-fix-angular-4-api-call-issues está quebrado (404).
Peter Mortensen
8

A aplicação de uma restrição CORS é um recurso de segurança definido por um servidor e implementado por um navegador .

O navegador examina a política do CORS do servidor e a respeita.

No entanto, a ferramenta Postman não se preocupa com a política do CORS do servidor.

É por isso que o erro CORS aparece no navegador, mas não no Postman.

Gopinath
fonte
1
Sim, não posso enfatizar o suficiente por que esse pequeno detalhe merece alguma atenção. Ao falar sobre segurança, é fundamental mencionar que o CORS é tão forte quanto o cliente que está implementando. Imagine que você pegue um HttpClient (código do lado do servidor) simples e crie um proxy, que fará suas solicitações ... A segurança pode ser completamente contornada, deixando realmente o padrão CORS como uma solução ruim
Christopher Bonitz,
7

Na investigação abaixo como API, uso http://example.com em vez de http: // myApiUrl / login da sua pergunta, porque esta primeira está funcionando.

Presumo que sua página esteja em http: //my-site.local: 8088 .

A razão pela qual você vê resultados diferentes é que o Postman:

  • definir cabeçalho Host=example.com(sua API)
  • NÃO definir cabeçalho Origin

Isso é semelhante à maneira como os navegadores enviam solicitações quando o site e a API têm o mesmo domínio (os navegadores também definem o item de cabeçalho Referer=http://my-site.local:8088, mas não o vejo no Postman). Quando o Origincabeçalho não está definido, geralmente os servidores permitem tais solicitações por padrão.

Digite a descrição da imagem aqui

Esta é a maneira padrão como o Postman envia solicitações. Mas um navegador envia solicitações de maneira diferente quando o site e a API têm domínios diferentes e, em seguida, ocorre o CORS e o navegador automaticamente:

  • define o cabeçalho Host=example.com(o seu como API)
  • define o cabeçalho Origin=http://my-site.local:8088(seu site)

(O cabeçalho Referertem o mesmo valor que Origin). E agora, na guia Console e redes do Chrome, você verá:

Digite a descrição da imagem aqui

Digite a descrição da imagem aqui

Quando você tem Host != Origino CORS, e quando o servidor detecta essa solicitação, geralmente a bloqueia por padrão .

Origin=nullé definido quando você abre o conteúdo HTML de um diretório local e envia uma solicitação. A mesma situação é quando você envia uma solicitação dentro de um <iframe>, como no snippet abaixo (mas aqui o Hostcabeçalho não está definido) - em geral, em todos os lugares em que a especificação HTML diz origem opaca, você pode traduzir isso para Origin=null. Mais informações sobre isso você pode encontrar aqui .

fetch('http://example.com/api', {method: 'POST'});
Look on chrome-console > network tab

Se você não usar uma solicitação CORS simples, geralmente o navegador também envia automaticamente uma solicitação OPTIONS antes de enviar a solicitação principal - mais informações estão aqui . O snippet abaixo mostra:

fetch('http://example.com/api', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json'}
});
Look in chrome-console -> network tab to 'api' request.
This is the OPTIONS request (the server does not allow sending a POST request)

Você pode alterar a configuração do seu servidor para permitir solicitações CORS.

Aqui está um exemplo de configuração que ativa o CORS no nginx (arquivo nginx.conf) - tenha muito cuidado com a configuração always/"$http_origin"do nginx e "*"do Apache - isso desbloqueará o CORS de qualquer domínio.

Aqui está um exemplo de configuração que ativa o CORS no Apache (arquivo .htaccess)

Kamil Kiełczewski
fonte
2

Foi encontrado o mesmo erro em diferentes casos de uso.

Caso de uso: no chrome, quando tentou chamar o ponto final do Spring REST em angular.

insira a descrição da imagem aqui

Solução: adicione a anotação @CrossOrigin ("*") na parte superior da respectiva classe Controller.

insira a descrição da imagem aqui

Kms
fonte
Eu uso localhost em vez de * por segurança
neo7bf
-1

Se você usa o .NET como camada intermediária, verifique o atributo route claramente, por exemplo,

Eu tive problemas quando era assim,

[Route("something/{somethingLong: long}")] //Space.

Corrigido por isso,

[Route("something/{somethingLong:long}")] //No space
Sai Vaibhav Medavarapu
fonte
-1

Somente para o projeto da API Web do .NET Core, adicione as seguintes alterações:

  1. Adicione o seguinte código após a services.AddMvc()linha no ConfigureServices()método do arquivo Startup.cs:
services.AddCors(allowsites=>{allowsites.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
            });
  1. Adicione o seguinte código após app.UseMvc()linha no Configure()método do arquivo Startup.cs:
app.UseCors(options => options.AllowAnyOrigin());
  1. Abra o controlador que você deseja acessar fora do domínio e adicione este atributo a seguir no nível do controlador:
[EnableCors("AllowOrigin")]
Shakti Srivastav
fonte