Cómo habilitar el uso compartido de recursos de origen cruzado (CORS) en el marco express.js en node.js

101

Estoy tratando de construir un servidor web en node.js que admita secuencias de comandos entre dominios, al mismo tiempo que proporciona archivos estáticos desde un directorio público. Estoy usando express.js y no estoy realmente seguro de cómo permitir las secuencias de comandos entre dominios ( Access-Control-Allow-Origin: *).

Vi esta publicación , que no me resultó útil.

var express = require('express')
  , app = express.createServer();

app.get('/', function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    next();
});

app.configure(function () {
    app.use(express.methodOverride());
    app.use(express.bodyParser());
    app.use(app.router);
});

app.configure('development', function () {

    app.use(express.static(__dirname + '/public'));
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function () {


    var oneYear = 31557600000;
    //    app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
    app.use(express.static(__dirname + '/public'));
    app.use(express.errorHandler());
});

app.listen(8888);
console.log('express running at http://localhost:%d', 8888);
Chico
fuente
Observe que app.all vs app.get. Es OPCIONES solicitar no OBTENER
Shimon Doodkin
consulte el servidor web local para ver un ejemplo de un servidor web estático de nodo simple que admite CORS
Lloyd
consulte enable-cors.org/server_apache.html para obtener más información
Mostafa

Respuestas:

159

Consulte el ejemplo de enable-cors.org :

En su aplicación ExpressJS en node.js, haga lo siguiente con sus rutas:

app.all('/', function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  next();
 });

app.get('/', function(req, res, next) {
  // Handle the get for this route
});

app.post('/', function(req, res, next) {
 // Handle the post for this route
});

La primera llamada ( app.all) debe realizarse antes que todas las demás rutas en su aplicación (o al menos las que desea que estén habilitadas para CORS).

[Editar]

Si desea que los encabezados también se muestren para archivos estáticos, intente esto (asegúrese de que sea antes de la llamada a use(express.static()):

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  next();
});

Probé esto con su código y obtuve los encabezados de los activos del publicdirectorio:

var express = require('express')
  , app = express.createServer();

app.configure(function () {
    app.use(express.methodOverride());
    app.use(express.bodyParser());
    app.use(function(req, res, next) {
      res.header("Access-Control-Allow-Origin", "*");
      res.header("Access-Control-Allow-Headers", "X-Requested-With");
      next();
    });
    app.use(app.router);
});

app.configure('development', function () {
    app.use(express.static(__dirname + '/public'));
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function () {
    app.use(express.static(__dirname + '/public'));
    app.use(express.errorHandler());
});

app.listen(8888);
console.log('express running at http://localhost:%d', 8888);

Por supuesto, podría empaquetar la función en un módulo para que pueda hacer algo como

// cors.js

module.exports = function() {
  return function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    next();
  };
}

// server.js

cors = require('./cors');
app.use(cors());
Michelle Tilley
fuente
Oye, gracias por tu respuesta. Hice lo que sugirió (primera parte, pero todavía no veo ninguna diferencia en los encabezados de solicitud). Adjunté mi código actual arriba. ¿Puede explicar cómo puedo integrar el resto de su solución a eso?
Guy
1
Me sorprende que, dado que está useusando app.routerantes express.static, no modifica los encabezados de los archivos estáticos; en cualquier caso, he actualizado mi respuesta para que funcione.
Michelle Tilley
¡Gracias! Veo que tienes razón. Los activos se obtienen del servidor con los encabezados solicitados. Puede que no haya sido claro sobre mi problema real. Estoy tratando de hacer una llamada API a un servidor externo con el comando get. y ahí es donde aparece el error: XMLHttpRequest no puede cargar SOMEURL.com . Origen localhost: 8888 no está permitido por Access-Control-Allow-Origin.
Guy
Puede que lo esté malinterpretando. ¿Tiene el control del servidor en SOMEURL.com?
Michelle Tilley
Lo siento, entiendo completamente tu respuesta ahora. Muchas gracias. Agradezco tu ayuda :)
Guy
58

Siguiendo la solución de @Michelle Tilley, aparentemente no funcionó para mí al principio. No estoy seguro de por qué, tal vez esté usando Chrome y una versión diferente de node. Después de algunos ajustes menores, ahora me está funcionando.

app.all('*', function(req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
});

En caso de que alguien enfrente un problema similar al mío, esto podría ser útil.

TonyTakeshi
fuente
Observe que app.all vs app.get. Es OPCIONES solicitar no OBTENER
Shimon Doodkin
Esto funciona para mí (estoy recuperando objetos usando Backbone). Estoy tratando de averiguar si funcionará en IE 8 ... parece que debería, pero no sé si se requiere algo especial para esta cosa "XDomainRequest" ... developer.mozilla.org/en- US / docs / HTTP /…
Adam Loving
ALGUNA INFORMACIÓN PARA FUTUROS USUARIOS: Estoy redirigiendo mi nombre de dominio a un repositorio de heroku, por lo que me encontré con este problema. De todos modos, la primera respuesta funcionó localmente, pero no después de que la empujé a heroku. Sin embargo, esta respuesta funcionó después de presionar a heroku.
Kris Hollenbeck
@KrisHollenbeck Esto no funciona para mí en heroku, ¿hiciste algo más?
Ben Craig
@BenCraig, No, pero en realidad dejó de funcionar para mí después del primer intento. Así que todavía tengo este problema.
Kris Hollenbeck
11

Pruebe estos módulos cors npm.

var cors = require('cors')

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

Este módulo proporciona muchas funciones para ajustar la configuración de cors, como la lista blanca de dominios, la habilitación de cors para apis específicas, etc.

Zahid Rahman
fuente
2

Yo uso esto:

var app = express();

app
.use(function(req, res, next){
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'X-Requested-With');
    next();
})
.options('*', function(req, res, next){
    res.end();
})
;

h.readFiles('controllers').forEach(function(file){
  require('./controllers/' + file)(app);
})
;

app.listen(port);
console.log('server listening on port ' + port);

este código asume que sus controladores están ubicados en el directorio de controladores. cada archivo en este directorio debería ser algo como esto:

module.exports = function(app){

    app.get('/', function(req, res, next){
        res.end('hi');
    });

}
Elmer
fuente
1

Recomiende usar el módulo cors express. Esto le permite incluir dominios en la lista blanca, permitir / restringir dominios específicamente a rutas, etc.

Jerome Anthony
fuente
0

Debe configurar Access-Control-Allow-Credentials: true, si desea utilizar "cookies" a través de "Credenciales"

app.all('*', function(req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
});
duque dios
fuente
0
app.use(function(req, res, next) {
var allowedOrigins = [
  "http://localhost:4200"
];
var origin = req.headers.origin;
console.log(origin)
console.log(allowedOrigins.indexOf(origin) > -1)
// Website you wish to allow to
if (allowedOrigins.indexOf(origin) > -1) {
  res.setHeader("Access-Control-Allow-Origin", origin);
}

// res.setHeader("Access-Control-Allow-Origin", "http://localhost:4200");

// 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,Authorization"
);

// 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();

});

Agregue este código en su archivo index.js o server.js y cambie la matriz de origen permitida de acuerdo con sus requisitos.

Atyos
fuente
-6

Un paso adicional que tenía que tomar era cambiar mi URL de http://localhostahttp://127.0.0.0

usuario3795430
fuente
¿A qué te refieres?
Blunderfest