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

2845

Mod note: This question is about why XMLHttpRequest/fetch/etc. on the browser are subject to the Same Access Policy restrictions (you get errors mentioning CORB or CORS) while Postman is not. This question is not about how to fix a "No 'Access-Control-Allow-Origin'..." error. It's about why they happen.

Please stop posting:

  • CORS configurations for every language/framework under the sun. Instead find your relevant language/framework's question.
  • 3rd party services that allow a request to circumvent CORS
  • Command line options for turning off CORS for various browsers

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

XMLHttpRequest cannot load http://myApiUrl/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

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

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);
    });
13
  • 42
    ¿Está haciendo la solicitud desde localhost o ejecutando HTML directamente? MD. Sahib Bin Mahboob 17/11/2013 a las 19:31
  • 1
    @ MD.SahibBinMahboob Si entiendo su pregunta, la solicito a localhost: tengo una página en mi computadora y simplemente la ejecuto. Cuando implemento el sitio en el alojamiento, dio el mismo resultado. Mr Jedi 17/11/2013 a las 19:43
  • 7
    muy relacionado: stackoverflow.com/questions/10143093/…cregox 07/07/2014 a las 16:39
  • 11
    Para cualquiera que busque más lectura, MDN tiene un buen artículo sobre ajax y solicitudes de origen cruzado: developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORSSam Eaton 18/06/15 a las 15:22
  • 6
    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 obtendrá este error cuando realice solicitudes desde su aplicación. Alex J 9 de mayo de 2017 a las 2:05
1495

Si lo entendí bien, estás haciendo una XMLHttpRequest a un dominio diferente al de tu página. Entonces, el navegador lo está bloqueando, ya que generalmente permite una solicitud en el mismo origen por razones de seguridad. Debe hacer algo diferente cuando desee realizar una solicitud entre dominios. Un tutorial sobre cómo lograrlo está usando CORS .

Cuando utiliza cartero, esta política no los restringe. Citado de XMLHttpRequest de origen cruzado :

Regular web pages can use the XMLHttpRequest object to send and receive data from remote servers, but they're limited by the same origin policy. Extensions aren't so limited. An extension can talk to remote servers outside of its origin, as long as it first requests cross-origin permissions.

5
  • 10
    Tienes razón. Hago una solicitud a un dominio diferente al de mi página. La API está en el servidor y ejecuto una solicitud desde localhost. Antes de aceptar la respuesta, ¿puede explicarme qué significa "ejecutar la solicitud directamente"? CARTERA no usa dominio? Mr Jedi 17/11/2013 a las 19:54
  • 207
    El navegador no bloquea 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 suscribirse a las solicitudes CORS en su servidor API devolviendo los encabezados adecuados según la solicitud. Debería leer sobre los conceptos de CORS en mzl.la/VOFrSz . El cartero también envía solicitudes a través de XHR. Si no ve el mismo problema al usar cartero, esto significa que, sin saberlo, no está enviando la misma solicitud a través de cartero. Ray Nicholus 17 de nov. De 2013 a las 20:01
  • 14
    @ 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 17 de noviembre de 2013 a las 20:08
  • 1
    Para obtener una solución que permita que el código JavaScript de su frontend acceda a una respuesta "bloqueada", consulte la sección Cómo usar un proxy CORS para solucionar los problemas de "No Access-Control-Allow-Origin encabezado" de la respuesta en stackoverflow.com / a / 43881141/441757sideshowbarker 20/08/20 a las 1:06
  • ¿Alguien puede explicar por qué solo el navegador necesita tal mecanismo de seguridad y no se bloqueará el uso del servidor (nodo) para enviar solicitudes? ¿El nodo es seguro? weiya ou 4 de mayo y 7:12
301

WARNING: Using Access-Control-Allow-Origin: * can make your API/website vulnerable to cross-site request forgery (CSRF) attacks. Make certain you understand the risks before using this code.

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 eliminando los comentarios de 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 Flask cors en su solicitud.

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 obtener más detalles, puede consultar la documentación de Flask .

2
  • 197
    No debe apagar CORS porque no sabe para qué sirve. Ésta es una respuesta terrible. meagar 30 de diciembre de 2014 a las 6:12
  • 151
    Aunque no sea seguro, la cuestión no se trata de seguridad, sino de cómo realizar la tarea. Esta es una de las opciones entre las 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. Sanitizo toda la entrada con PHP en el dominio de destino, así que, si alguien quiere publicar algo de basura, 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 26 feb.15 a las 16:37
85

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

Ambos son diferentes. Postman llama a "POST" correctamente, pero cuando lo llamemos, será "OPTIONS".

Para servicios web C #: API web

Agregue el siguiente código en su archivo web.config en 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 de 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 está buscando descargar contenido de un sitio web de terceros , esto no lo 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");
0
31

En la siguiente investigación como API, uso http://example.com en lugar de http: // myApiUrl / login de su pregunta, porque esta primera está funcionando.

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 este tipo de 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 tuyo 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 lo tiene, Host != Origines CORS, y cuando el servidor detecta una solicitud de este tipo, generalmente la bloquea de forma 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 de abajo (pero aquí el Hostencabezado no está configurado en absoluto); en general, en todos los lugares donde la especificación HTML dice origen opaco, puede traducirlo a 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; más información está aquí . El fragmento de abajo 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 una configuración de ejemplo 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.

location ~ ^/index\.php(/|$) {
   ...
    add_header 'Access-Control-Allow-Origin' "$http_origin" always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    if ($request_method = OPTIONS) {
        add_header 'Access-Control-Allow-Origin' "$http_origin"; # DO NOT remove THIS LINES (doubled with outside 'if' above)
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Max-Age' 1728000; # cache preflight value for 20 days
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'My-First-Header,My-Second-Header,Authorization,Content-Type,Accept,Origin';
        add_header 'Content-Length' 0;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        return 204;
    }
}

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

# ------------------------------------------------------------------------------
# | Cross-domain Ajax requests                                                 |
# ------------------------------------------------------------------------------

# Enable cross-origin Ajax requests.
# http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity
# http://enable-cors.org/

# <IfModule mod_headers.c>
#    Header set Access-Control-Allow-Origin "*"
# </IfModule>

# Header set Header set Access-Control-Allow-Origin "*"
# Header always set Access-Control-Allow-Credentials "true"

Access-Control-Allow-Origin "http://your-page.com:80"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header always set Access-Control-Allow-Headers "My-First-Header,My-Second-Header,Authorization, content-type, csrf-token"
22

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

The browser looks at the CORS policy of the server and respects it.

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

Por eso aparece el error CORS en el navegador, pero no en Postman.

0
15

Si desea omitir esa restricción al obtener el contenido con fetch API o XMLHttpRequest en javascript, puede usar un servidor proxy para que establezca el encabezado Access-Control-Allow-Originen *.

const express = require('express');
const request = require('request');

const app = express();

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  next();
});

app.get('/fetch', (req, res) => {
  request(
    { url: req.query.url },
    (error, response, body) => {
      if (error || response.statusCode !== 200) {
        return res.status(500).send('error');
      }
      res.send(body);
    }
  )
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`listening on ${PORT}`));

Arriba hay un código de muestra (se requiere el nodo J) que puede actuar como un servidor proxy. Por ejemplo: si quiero buscar https://www.google.comnormalmente, se produce un error CORS, pero ahora que la solicitud se envía a través del servidor proxy alojado localmente en el puerto 3000, el servidor proxy agrega el Access-Control-Allow-Originencabezado en la respuesta y no habrá ningún problema.

Envíe una solicitud GET a http: // localhost: 3000 / fetch? Url = Your URL here, en lugar de enviar directamente la solicitud a la URL que desea obtener.

Your URL here representa la URL que desea obtener, por ejemplo: https://www.google.com

14

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

Caso de uso: en Chrome cuando se intentó llamar al punto final de 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 respectiva.

ingrese la descripción de la imagen aquí

0
14

El error que obtiene se debe al estándar CORS, que establece algunas restricciones sobre cómo JavaScript puede realizar solicitudes ajax.

El estándar CORS es un estándar del lado del cliente, implementado en el navegador. Por lo tanto, es el navegador el que evita que la llamada se complete y genera el mensaje de error, no el servidor.

Postman no implementa las restricciones CORS, por lo que no ve el mismo error al realizar la misma llamada desde Postman.

¿ Por qué Postman no implementa CORS? CORS define las restricciones relativas al origen (dominio URL) de la página que inicia la solicitud. Pero en Postman, las solicitudes no se originan en una página con una URL, por lo que CORS no se aplica.

2
  • Eso es lo que dijo la respuesta aceptada;)Mr Jedi 11 de enero a las 10:10
  • 3
    @MrJedi: La respuesta aceptada no explica por qué la solicitud tiene éxito en Postman, que era la pregunta original. JacquesB 11 de enero a las 10:24
4

Solo para el proyecto de API web de .NET Core, 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 siguiente atributo en el nivel del controlador:
[EnableCors("AllowOrigin")]
-1

Si usa .NET como su nivel medio, 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
-2

¿Está utilizando fuentes web de Google, Typekit, etc.? Hay varias formas en las que puede usar fuentes web como los métodos @ font-face o CSS3, algunos navegadores como Firefox e IE pueden negarse a incrustar la fuente cuando proviene de alguna URL de terceros no estándar (como su blog) por la misma razón de seguridad.

Para solucionar un problema de su blog de WordPress, simplemente colóquelo a continuación en su archivo .htaccess.

<IfModule mod_headers.c>
  <FilesMatch "\.(ttf|ttc|otf|eot|woff|woff2|font.css|css|js)$">
  Header set Access-Control-Allow-Origin "*"
  </FilesMatch>
</IfModule>

Fuente: https://crunchify.com/how-to-fix-access-control-allow-origin-issue-for-your-https-enabled-wordpress-site-and-maxcdn/