No 'Access-Control-Allow-Origin' - Problema de nodo / puerto de Apache

260

He creado una pequeña API usando Node / Express y tratando de extraer datos usando Angularjs, pero como mi página html se ejecuta bajo apache en localhost: 8888 y la API de nodo está escuchando en el puerto 3000, obtengo el No 'Control de acceso- Permitir origen '. Intenté usar node-http-proxyApache y Vhosts pero no tengo mucho éxito, vea el error completo y el código a continuación.

XMLHttpRequest no puede cargar localhost: 3000. No hay encabezado 'Access-Control-Allow-Origin' presente en el recurso solicitado. El origen 'localhost: 8888' no tiene acceso permitido ".

// Api Using Node/Express    
var express = require('express');
var app = express();
var contractors = [
    {   
     "id": "1", 
        "name": "Joe Blogg",
        "Weeks": 3,
        "Photo": "1.png"
    }
];

app.use(express.bodyParser());

app.get('/', function(req, res) {
  res.json(contractors);
});
app.listen(process.env.PORT || 3000);
console.log('Server is running on Port 3000')

Código angular

angular.module('contractorsApp', [])
.controller('ContractorsCtrl', function($scope, $http,$routeParams) {

   $http.get('localhost:3000').then(function(response) {
       var data = response.data;
       $scope.contractors = data;
   })

HTML

<body ng-app="contractorsApp">
    <div ng-controller="ContractorsCtrl"> 
        <ul>
            <li ng-repeat="person in contractors">{{person.name}}</li>
        </ul>
    </div>
</body>
usuario1336103
fuente

Respuestas:

622

Intente agregar el siguiente middleware a su aplicación NodeJS / Express (he agregado algunos comentarios para su conveniencia):

// Add headers
app.use(function (req, res, next) {

    // Website you wish to allow to connect
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8888');

    // Request methods you wish to allow
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

    // Request headers you wish to allow
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

    // Set to true if you need the website to include cookies in the requests sent
    // to the API (e.g. in case you use sessions)
    res.setHeader('Access-Control-Allow-Credentials', true);

    // Pass to next layer of middleware
    next();
});

¡Espero que ayude!

jvandemo
fuente
2
¿Puedes ayudar a especificar exactamente a dónde va eso? Tengo el siguiente código en mi servidor. ¿Va justo después de esto? var app = require ('express') (), server = require ('http'). createServer (app), io = require ('socket.io'). listen (server), request = require ("request") , url = require ("url"); server.listen (6969); // ¿va aquí? en una nueva línea?
Art Geigel
1
@jvandemo ¿tengo que cambiar la aplicación.get ('/', function (req, res) a ... function (req, res, next)?
Sangram Singh
10
Eres mi persona favorita en este momento. Gracias. ¿Podemos agregar una nota de que este código tiene que suceder antes de que se definan las rutas para novatos como yo?
gegillam
1
¿Cómo hacer que esto funcione mientras se usa el módulo de solicitud?
Rohit Tigga el
2
No funcionó en mi caso. Todavía aparece este error: "La respuesta a la solicitud de verificación previa no pasa la verificación de control de acceso: no hay encabezado 'Access-Control-Allow-Origin' presente en el recurso solicitado. Por lo tanto, el origen ' abc.xyz.net:212 ' no está permitido acceso. La respuesta tenía el código de estado HTTP 500. "
user1451111
96

La respuesta aceptada está bien, en caso de que prefiera algo más corto, puede usar un complemento llamado cors disponible para Express.js

Es fácil de usar, para este caso particular:

var cors = require('cors');

// use it before all route definitions
app.use(cors({origin: 'http://localhost:8888'}));
Fabiano Soriani
fuente
3
Tuve que usarlo {origin: 'null'}para que funcione ... Aparentemente, ¿mi navegador envía nullcomo origen?
Ricardo Cruz
2
Por qué reinventar la rueda. Siempre estoy a favor de una solución empaquetada en comparación con el fragmento de código
Pierre
pequeña biblioteca dulce que manejó mi caso de uso de querer diferentes métodos de diferentes orígenes bastante bien ... y menos fatiga del código para el siguiente tipo que lo mira.
Kyle Baker,
66
Gracias, app.use(cors({origin: '*'}));trabajó para mí, según enable-cors .
danialk
2
Sugiero echar un vistazo a la página de npm cors para aprovecharla mejor. Me dejó las cosas muy claras =).
13013SwagR
30

Otra forma es simplemente agregar los encabezados a su ruta:

router.get('/', function(req, res) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); // If needed
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); // If needed
    res.setHeader('Access-Control-Allow-Credentials', true); // If needed

    res.send('cors problem fixed:)');
});
Asaf Hananel
fuente
8
)de smiley me confundió
diEcho
17

La respuesta principal funcionó bien para mí, excepto que necesitaba incluir en la lista blanca más de un dominio.

Además, la respuesta principal adolece del hecho de que la OPTIONSsolicitud no es manejada por el middleware y no la obtienes automáticamente.

Almacene dominios allowed_originsen la lista blanca como en la configuración Express y pongo el dominio correcto de acuerdo con el originencabezado, ya Access-Control-Allow-Originque no permite especificar más de un dominio.

Esto es lo que terminé con:

var _ = require('underscore');

function allowCrossDomain(req, res, next) {
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');

  var origin = req.headers.origin;
  if (_.contains(app.get('allowed_origins'), origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
  }

  if (req.method === 'OPTIONS') {
    res.send(200);
  } else {
    next();
  }
}

app.configure(function () {
  app.use(express.logger());
  app.use(express.bodyParser());
  app.use(allowCrossDomain);
});
Dan Abramov
fuente
¿Es este el mismo 'if (app.get (' orígenes permitidos '). IndexOf (origin)! == - 1)?'?
Rune Jeppesen
13

El código de respuesta solo permite localhost: 8888. Este código no se puede implementar en la producción o en un servidor y nombre de puerto diferentes.

Para que funcione para todas las fuentes, use esto en su lugar:

// Add headers
app.use(function (req, res, next) {

    // Website you wish to allow to connect
    res.setHeader('Access-Control-Allow-Origin', '*');

    // Request methods you wish to allow
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

    // Request headers you wish to allow
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

    // Set to true if you need the website to include cookies in the requests sent
    // to the API (e.g. in case you use sessions)
    res.setHeader('Access-Control-Allow-Credentials', true);

    // Pass to next layer of middleware
    next();
});
Vicheanak
fuente
2
¡Esto no funciona para mi! "* no es un origen válido". Parece que el carácter * no se reconoce como comodín.
Francesco
Esto funciona para mi. es decir, usando el comodín '*'. Funciona tanto para cromo como para safari.
AnBisw
Gracias;) Funciona bien
Mauro
9

Instale la dependencia de cors en su proyecto:

npm i --save cors

Agregue a su archivo de configuración del servidor lo siguiente:

var cors = require('cors');
app.use(cors());

Funciona para mí con la versión 2.8.4 cors.

monikaja
fuente
"cors": "^2.8.5", "express": "^4.16.3",funciona bien solo con la línea que @monikaja sugirió. ¡Gracias!
RamiroIsBack
Lo que esto hace es permitir que todos los orígenes / dominios accedan a la aplicación, que es algo que generalmente no desea hacer. En su lugar, especifique solo los dominios permitidos.
Lacho Tomov
7

Esto funcionó para mí.

app.get('/', function (req, res) {

    res.header("Access-Control-Allow-Origin", "*");
    res.send('hello world')
})

Puede cambiar * para satisfacer sus necesidades. Espero que esto pueda ayudar.

dmx
fuente
7

Hola, esto sucede cuando el front-end y el back-end se ejecutan en diferentes puertos. El navegador bloquea las respuestas del back-end debido a la ausencia en los encabezados CORS. La solución es hacer agregar los encabezados CORS en la solicitud de back-end. La forma más fácil es usar el paquete cors npm.

var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())

Esto habilitará los encabezados CORS en toda su solicitud. Para obtener más información, puede consultar la documentación de cors

https://www.npmjs.com/package/cors

Karthik
fuente
3
app.all('*', function(req, res,next) {
    /**
     * Response settings
     * @type {Object}
     */
    var responseSettings = {
        "AccessControlAllowOrigin": req.headers.origin,
        "AccessControlAllowHeaders": "Content-Type,X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5,  Date, X-Api-Version, X-File-Name",
        "AccessControlAllowMethods": "POST, GET, PUT, DELETE, OPTIONS",
        "AccessControlAllowCredentials": true
    };

    /**
     * Headers
     */
    res.header("Access-Control-Allow-Credentials", responseSettings.AccessControlAllowCredentials);
    res.header("Access-Control-Allow-Origin",  responseSettings.AccessControlAllowOrigin);
    res.header("Access-Control-Allow-Headers", (req.headers['access-control-request-headers']) ? req.headers['access-control-request-headers'] : "x-requested-with");
    res.header("Access-Control-Allow-Methods", (req.headers['access-control-request-method']) ? req.headers['access-control-request-method'] : responseSettings.AccessControlAllowMethods);

    if ('OPTIONS' == req.method) {
        res.send(200);
    }
    else {
        next();
    }


});
Wiki
fuente
2

Agregue el siguiente código en app.js de NODEJ API relajante para evitar el error "Access-Control-Allow-Origin" en angular 6 o cualquier otro marco

var express = require('express');
var app = express();

var cors = require('cors');
var bodyParser = require('body-parser');

//enables cors
app.use(cors({
  'allowedHeaders': ['sessionId', 'Content-Type'],
  'exposedHeaders': ['sessionId'],
  'origin': '*',
  'methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
  'preflightContinue': false
}));
Ezhil Arasan
fuente
1

Puede usar "$ http.jsonp"

O

A continuación se muestra la solución para Chrome para pruebas locales

Debes abrir tu Chrome con el siguiente comando. (Presione ventana + R)

Chrome.exe --allow-file-access-from-files

Nota: su Chrome no debe estar abierto. Cuando ejecute este comando, Chrome se abrirá automáticamente.

Si está ingresando este comando en el símbolo del sistema, seleccione su directorio de instalación de Chrome y luego use este comando.

Debajo del código de script para abrir Chrome en MAC con "--allow-file-access-from-files"

set chromePath to POSIX path of "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" 
set switch to " --allow-file-access-from-files"
do shell script (quoted form of chromePath) & switch & " > /dev/null 2>&1 &"

segundas opciones

Puede usar open (1) para agregar las banderas: open -a 'Google Chrome' --args --allow-file-access-from-files

JQuery Guru
fuente
¿Qué tal en MAC? Chrome.exe --allow-file-access-from-files
user1336103
/ Aplicaciones / Google \ Chrome.app/Contents/MacOS/Google \ Chrome --allow-file-access-from-files logra abrir Chrome pero el mensaje sigue mostrando "XMLHttpRequest no puede cargar localhost: 3000. Origen localhost: 8888 es no permitido por Access-Control-Allow-Origin. "
usuario1336103
+1 Puedo confirmar que esto funciona con la opción Mac usando 'abrir'. Mi caso es un poco diferente, ya que simplemente estoy probando un sitio completamente descargado que accede a algunos archivos JSON locales.
Spong
0

/**
 * Allow cross origin to access our /public directory from any site.
 * Make sure this header option is defined before defining of static path to /public directory
 */
expressApp.use('/public',function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    // Request headers you wish to allow
    res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    // Set to true if you need the website to include cookies in the requests sent
    res.setHeader('Access-Control-Allow-Credentials', true);
    // Pass to next layer of middleware
    next();
});


/**
 * Server is about set up. Now track for css/js/images request from the 
 * browser directly. Send static resources from "./public" directory. 
 */
expressApp.use('/public', express.static(path.join(__dirname, 'public')));
If you want to set Access-Control-Allow-Origin to a specific static directory you can set the following.

Luton Datta
fuente