¿Por qué Postman no recibe un error "No hay encabezado 'Access-Control-Allow-Origin' presente en el recurso solicitado" cuando mi código JavaScript lo hace?

2503

Nota de modificación : esta pregunta es acerca de por qué Postman no está sujeto a restricciones CORS de la misma manera que lo está XMLHttpRequest. Esta pregunta no se trata de cómo solucionar un error "No 'Access-Control-Allow-Origin' ...".

Por favor, deja de publicar :


Estoy tratando de hacer una autorización usando JavaScript conectándome al Frasco incorporado RESTful API . Sin embargo, cuando hago la solicitud, aparece el siguiente error:

XMLHttpRequest no puede cargar http: // myApiUrl / login . No hay encabezado 'Access-Control-Allow-Origin' presente en el recurso solicitado. Por lo tanto, el origen 'nulo' no tiene acceso permitido.

Sé que la API o el recurso remoto deben establecer el encabezado, pero ¿por qué funcionó cuando hice la solicitud a través de la extensión de Chrome Postman ?

Este es el código de solicitud:

$.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);
    });
Señor jedi
fuente
32
¿Está haciendo la solicitud de localhost o está ejecutando directamente HTML?
MD. Sahib Bin Mahboob
@ MD.SahibBinMahboob Si entiendo su pregunta, solicito a localhost: tengo una página en mi computadora y simplemente la ejecuto. Cuando despliegue el sitio en hosting, me da el mismo resultado.
Sr. Jedi
66
muy relacionado: stackoverflow.com/questions/10143093/…
cregox
8
Para cualquiera que busque más lectura, MDN tiene un buen artículo sobre todas las solicitudes de origen cruzado y ajax: developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Sam Eaton
1
Una nota importante para este tipo de error en el nodo js. DEBE configurar sus encabezados de acceso en el inicio de su archivo server.js ANTES de comenzar a configurar sus rutas. De lo contrario, todo funcionará muy bien, pero recibirá este error cuando realice solicitudes desde su aplicación.
Alex J

Respuestas:

1346

Si lo entendí bien, está haciendo una solicitud XMLHttpRequest a un dominio diferente al de su página. Por lo tanto, el navegador lo bloquea, ya que generalmente permite una solicitud en el mismo origen por razones de seguridad. Debe hacer algo diferente cuando desea hacer una solicitud de dominio cruzado. Un tutorial sobre cómo lograr eso es Usar CORS .

Cuando utiliza cartero, no están restringidos por esta política. Citado de Cross-Origin XMLHttpRequest :

Las páginas web normales pueden usar el objeto XMLHttpRequest para enviar y recibir datos de servidores remotos, pero están limitadas por la misma política de origen. Las extensiones no son tan limitadas. Una extensión puede comunicarse con servidores remotos fuera de su origen, siempre que solicite primero permisos de origen cruzado.

MARYLAND. Sahib Bin Mahboob
fuente
77
Tienes razón. Hago una solicitud a un dominio diferente al de mi página. API está en el servidor y ejecuto la solicitud de localhost. Antes de aceptar la respuesta, ¿puede explicarme qué significa "ejecutar la solicitud directamente"? ¿POSTMAN no usa dominio?
Sr. Jedi
181
El navegador no está bloqueando la solicitud. Los únicos navegadores que bloquean directamente las solicitudes ajax de origen cruzado son IE7 o anteriores. Todos los navegadores, excepto IE7 y anteriores, implementan la especificación CORS (IE8 e IE9 parcialmente). Todo lo que necesita hacer es aceptar las solicitudes de CORS en su servidor API devolviendo los encabezados adecuados en función de la solicitud. Debe leer sobre los conceptos de CORS en mzl.la/VOFrSz . Cartero envía solicitudes a través de XHR también. Si no ve el mismo problema cuando utiliza cartero, esto significa que, sin saberlo, no está enviando la misma solicitud a través de cartero.
Ray Nicholus
10
@ MD.SahibBinMahboob Postman NO está enviando una solicitud "desde su código java / python". Está enviando la solicitud directamente desde el navegador. XHR en las extensiones de Chrome funciona de manera un poco diferente, especialmente cuando se trata de solicitudes de origen cruzado .
Ray Nicholus
250

ADVERTENCIA: El uso Access-Control-Allow-Origin: *puede hacer que su API / sitio web sea vulnerable a los ataques de falsificación de solicitudes entre sitios (CSRF). Asegúrese de comprender los riesgos antes de usar este código.

Es muy simple de resolver si está usando PHP . Simplemente agregue el siguiente script al comienzo de su página PHP que maneja la solicitud:

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

Si está utilizando Node-red , debe permitir CORS en el node-red/settings.jsarchivo descomentando las siguientes líneas:

// 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"
},

Si está utilizando Flask igual que la pregunta; primero tienes que instalarflask-cors

$ pip install -U flask-cors

Luego incluya los frascos en su aplicación.

from flask_cors import CORS

Una aplicación simple se verá así:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

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

Para más detalles, puede consultar la documentación del Frasco .

Sheriff sombrío
fuente
93
y no es seguro
llazzaro
153
No debe apagar CORS porque no sabe para qué sirve. Esta es una respuesta terrible.
meagar
124
Aunque podría no ser seguro, la pregunta no era sobre seguridad, sino cómo realizar la tarea. Esta es una de las opciones que un desarrollador tiene que elegir cuando se trata de solicitudes AJAX entre dominios. Me ayudó a resolver el problema y, para mi aplicación, no me importa de dónde provienen los datos. Desinfecto todas las entradas con PHP en el dominio de destino, por lo tanto, si alguien quiere publicar algo basura en él, déjelo intentar. El punto principal aquí es que se puede permitir AJAX entre dominios desde el dominio de destino. +1 por la respuesta.
ZurabWeb
23
Si bien estoy de acuerdo con el mensaje general que está dando Piero, que no se trata específicamente de seguridad, sino que la seguridad es una preocupación. Creo que esto al menos debería haber dicho algo como "¡Esto es generalmente malo! ¡No hagas esto a menos que sepas lo que estás haciendo! Aquí hay más documentación al respecto: ...", y tal vez explique brevemente por qué. Odiaría que alguien viniera aquí y simplemente pensara "¡Oh, puedo agregar / ajustar este encabezado y estoy bien!" y no saber las ramificaciones completas. Quiero decir, es algo sobre ellos investigar y todo, pero aún así.
Thomas F.
44
Me gusta esta respuesta ... Tengo el mismo problema y lo resuelve ... Explicó que hay algunos problemas de seguridad, pero ese es otro problema y deja que todos individualmente piensen y resuelvan ese problema ...
Ari Waisberg
64

Porque
$ .ajax ({type: "POST" - llama a OPTIONS
$ .post ( - Llama a POST

Ambos son diferentes El cartero llama "POST" correctamente, pero cuando lo llamemos, será "OPCIONES".

Para servicios web C #: API web

Agregue el siguiente código en su archivo web.config bajo la etiqueta <system.webServer>. Esto funcionará:

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

Asegúrate de no cometer ningún error en la llamada 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: Si usted está buscando para la descarga de contenidos desde un sitio web de terceros a continuación, esto no le ayudará . Puede probar el siguiente código, pero no JavaScript.

System.Net.WebClient wc = new System.Net.WebClient();
string str = wc.DownloadString("http://mysite.microsoft.sample.xyz.com/api/mycall");
George Livingston
fuente
Esta configuración resolvió el mismo error en Wordpress en Azure Services. Gracias.
Andre Mesquita
99
Sugeriría usar un valor de origen específico para evitar solicitudes de dominios externos. Entonces, por ejemplo, en lugar de *usarhttps://www.myotherdomain.com
pechar el
El enlace hubfly.com/blog/solutions/how-to-fix-angular-4-api-call-issues está roto (404).
Peter Mortensen el
8

La aplicación de una restricción CORS es una característica de seguridad definida por un servidor e implementada por un navegador .

El navegador mira la política CORS del servidor y la respeta.

Sin embargo, la herramienta Postman no se preocupa por la política CORS del servidor.

Es por eso que el error CORS aparece en el navegador, pero no en Postman.

Gopinath
fuente
1
Sí, no puedo enfatizar lo suficiente por qué este pequeño detalle merece algo de atención. Cuando se habla de seguridad, es primordial mencionar que CORS es tan fuerte como el cliente que lo implementa. Así que imagine que toma un HttpClient simple (código del lado del servidor) y crea un proxy, que luego hace sus solicitudes ... La seguridad se puede eludir por completo, dejando realmente el estándar CORS como una solución deficiente
Christopher Bonitz
7

En la investigación a continuación como API, uso http://example.com en lugar de http: // myApiUrl / login de su pregunta, porque esta primera funciona.

Supongo que su página está en http: //my-site.local: 8088 .

La razón por la que ves resultados diferentes es que Postman:

  • establecer encabezado Host=example.com(su API)
  • NO establecer encabezado Origin

Esto es similar a la forma en que los navegadores envían solicitudes cuando el sitio y la API tienen el mismo dominio (los navegadores también configuran el elemento del encabezado Referer=http://my-site.local:8088, sin embargo, no lo veo en Postman). Cuando el Originencabezado no está configurado, generalmente los servidores permiten tales solicitudes de forma predeterminada.

Ingrese la descripción de la imagen aquí

Esta es la forma estándar en que Postman envía solicitudes. Pero un navegador envía solicitudes de manera diferente cuando su sitio y API tienen dominios diferentes , y luego se produce CORS y el navegador automáticamente:

  • establece el encabezado Host=example.com(el suyo como API)
  • establece encabezado Origin=http://my-site.local:8088(su sitio)

(El encabezado Referertiene el mismo valor que Origin). Y ahora, en la pestaña Consola y redes de Chrome, verá:

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

Cuando tiene Host != Originesto es CORS, y cuando el servidor detecta dicha solicitud, generalmente la bloquea de manera predeterminada .

Origin=nullse establece cuando abre contenido HTML desde un directorio local y envía una solicitud. La misma situación es cuando envía una solicitud dentro de un <iframe>, como en el fragmento a continuación (pero aquí el Hostencabezado no está configurado en absoluto); en general, en todos los lugares donde la especificación HTML dice origen opaco, puede traducir eso Origin=null. Puede encontrar más información sobre esto aquí .

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

Si no utiliza una solicitud CORS simple, generalmente el navegador también envía automáticamente una solicitud de OPCIONES antes de enviar la solicitud principal; aquí encontrará más información . El fragmento a continuación lo muestra:

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)

Puede cambiar la configuración de su servidor para permitir solicitudes CORS.

Aquí hay un ejemplo de configuración que activa CORS en nginx (archivo nginx.conf) - tenga mucho cuidado con la configuración always/"$http_origin"de nginx y "*"Apache - esto desbloqueará CORS de cualquier dominio.

Aquí hay una configuración de ejemplo que activa CORS en Apache (archivo .htaccess)

Kamil Kiełczewski
fuente
2

Encontró el mismo error en un caso de uso diferente.

Caso de uso: en cromo cuando se intenta llamar al punto final Spring REST en angular.

ingrese la descripción de la imagen aquí

Solución: agregue la anotación @CrossOrigin ("*") en la parte superior de la clase de controlador correspondiente.

ingrese la descripción de la imagen aquí

Kms
fuente
Uso localhost en lugar de * por seguridad
neo7bf
-1

Si usa .NET como nivel intermedio, verifique claramente el atributo de ruta, por ejemplo,

Tuve un problema cuando fue así,

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

Arreglado por esto,

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

Solo para el proyecto .NET Core Web API, agregue los siguientes cambios:

  1. Agregue el siguiente código después de la services.AddMvc()línea en el ConfigureServices()método del archivo Startup.cs:
services.AddCors(allowsites=>{allowsites.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
            });
  1. Agregue el siguiente código después de la app.UseMvc()línea en el Configure()método del archivo Startup.cs:
app.UseCors(options => options.AllowAnyOrigin());
  1. Abra el controlador al que desea acceder fuera del dominio y agregue este atributo siguiente en el nivel del controlador:
[EnableCors("AllowOrigin")]
Shakti Srivastav
fuente