web-dev-qa-db-fra.com

Pourquoi l'ajout d'en-têtes CORS à un itinéraire OPTIONS ne permet-il pas aux navigateurs d'accéder à mon API?

J'essaie de prendre en charge CORS dans mon application Node.js utilisant le framework Web Express.js. J'ai lu ne discussion de groupe sur Google sur la façon de gérer cela, et j'ai lu quelques articles sur le fonctionnement de CORS. Premièrement, j'ai fait ceci (le code est écrit en syntaxe CoffeeScript):

app.options "*", (req, res) ->
  res.header 'Access-Control-Allow-Origin', '*'
  res.header 'Access-Control-Allow-Credentials', true
  # try: 'POST, GET, PUT, DELETE, OPTIONS'
  res.header 'Access-Control-Allow-Methods', 'GET, OPTIONS'
  # try: 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept'
  res.header 'Access-Control-Allow-Headers', 'Content-Type'
  # ...

Cela ne semble pas fonctionner. Il semble que mon navigateur (Chrome) n'envoie pas la demande initiale OPTIONS. Lorsque je viens de mettre à jour le bloc de la ressource, je dois soumettre une demande GET d'origine croisée à:

app.get "/somethingelse", (req, res) ->
  # ...
  res.header 'Access-Control-Allow-Origin', '*'
  res.header 'Access-Control-Allow-Credentials', true
  res.header 'Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS'
  res.header 'Access-Control-Allow-Headers', 'Content-Type'
  # ...

Cela fonctionne (dans Chrome). Cela fonctionne également dans Safari.

J'ai lu ça ...

Dans un navigateur implémentant CORS, chaque demande GET ou POST d'origine croisée est précédée d'une demande OPTIONS qui vérifie si le paramètre GET ou POST est correct.

Ma principale question est donc: pourquoi cela ne semble-t-il pas se produire dans mon cas? Pourquoi mon bloc app.options n'est-il pas appelé? Pourquoi dois-je définir les en-têtes de mon bloc principal app.get?

594
mikong

Pour répondre à votre question principale, la spécification CORS ne requiert que l'appel OPTIONS précédant le POST ou GET si le POST ou le GET contient un contenu ou des en-têtes non simples.

Les types de contenu qui requièrent une demande de pré-vol CORS (l'appel OPTIONS) sont tous types de contenu , à l'exception des suivants :

  1. application/x-www-form-urlencoded
  2. multipart/form-data
  3. text/plain

Tout type de contenu autre que ceux énumérés ci-dessus déclenchera une demande préalable au vol.

En ce qui concerne les en-têtes, tous les en-têtes de demande , à l'exception des suivants , déclencheront une demande de pré-vol:

  1. Accept
  2. Accept-Language
  3. Content-Language
  4. Content-Type
  5. DPR
  6. Save-Data
  7. Viewport-Width
  8. Width

Toute autre en-tête de demande déclenchera la demande préalable au vol.

Vous pouvez donc ajouter un en-tête personnalisé, tel que: x-Trigger: CORS, ce qui devrait déclencher la demande de pré-vol et appuyer sur le bloc OPTIONS.

Voir Référence de l'API Web MDN - Requêtes avec contrôle en amont CORS

152
Dobes Vandermeer

J'ai trouvé le moyen le plus simple est d'utiliser le package node.js cors . L'utilisation la plus simple est:

var cors = require('cors')

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

Il existe bien sûr plusieurs façons de configurer le comportement selon vos besoins. la page liée ci-dessus montre un certain nombre d'exemples.

641
Wayne Maurer

Essayez de passer le contrôle à la prochaine route correspondante. Si Express correspond à route app.get en premier, il ne continuera pas sur la route des options à moins que vous ne le fassiez (notez l'utilisation de next):

app.get('somethingelse', function(req, res, next) {
    //..set headers etc.

    next();
});

Pour ce qui est d’organiser le matériel de la SCRO, je l’ai mis dans un middleware qui fonctionne bien pour moi:

//CORS middleware
var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', 'example.com');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');

    next();
}

//...
app.configure(function() {
    app.use(express.bodyParser());
    app.use(express.cookieParser());
    app.use(express.session({ secret: 'cool beans' }));
    app.use(express.methodOverride());
    app.use(allowCrossDomain);
    app.use(app.router);
    app.use(express.static(__dirname + '/public'));
});
426
evilcelery

Pour rester dans la même idée de routage. J'utilise ce code:

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

Similaire à http://enable-cors.org/server_expressjs.html exemple

111
Lialon

faire

npm install cors --save

et ajoutez simplement ces lignes dans votre fichier principal où votre demande va (conservez-la avant toute route).

const cors = require('cors');
const express = require('express');
let app = express();
app.use(cors());
app.options('*', cors());
78
Yatender Singh

J'ai créé un middleware plus complet, adapté à Express ou Connect. Il supporte les requêtes OPTIONS pour le contrôle en amont. Notez que cela autorisera l'accès de CORS à n'importe quoi, vous voudrez peut-être faire des vérifications si vous voulez limiter l'accès.

app.use(function(req, res, next) {
    var oneof = false;
    if(req.headers.Origin) {
        res.header('Access-Control-Allow-Origin', req.headers.Origin);
        oneof = true;
    }
    if(req.headers['access-control-request-method']) {
        res.header('Access-Control-Allow-Methods', req.headers['access-control-request-method']);
        oneof = true;
    }
    if(req.headers['access-control-request-headers']) {
        res.header('Access-Control-Allow-Headers', req.headers['access-control-request-headers']);
        oneof = true;
    }
    if(oneof) {
        res.header('Access-Control-Max-Age', 60 * 60 * 24 * 365);
    }

    // intercept OPTIONS method
    if (oneof && req.method == 'OPTIONS') {
        res.send(200);
    }
    else {
        next();
    }
});
49
mcfedr

installez le module cors d’expressjs. vous pouvez suivre ces étapes>

Installation

npm install cors

Utilisation simple (Activer toutes les demandes CORS)

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

pour plus de détails, allez à https://github.com/expressjs/cors

35
rahuL islam

Faites quelque chose comme ça:

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

d'abord, installez simplement cors dans votre projet. Prenez terminal (Invite de commande) et cd dans le répertoire de votre projet et exécutez la commande ci-dessous:

npm install cors --save

Ensuite, prenez le fichier server.js et changez le code pour y ajouter ce qui suit:

var cors = require('cors');


var app = express();

app.use(cors());

app.use(function(req, res, next) {
   res.header("Access-Control-Allow-Origin", "*");
   res.header('Access-Control-Allow-Methods', 'DELETE, PUT, GET, POST');
   res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
   next();
});

Cela a fonctionné pour moi ..

18
Reneesh TK

Test effectué avec express + node + ionic s'exécutant dans différents ports.

Localhost:8100

Localhost:5000

// CORS (Cross-Origin Resource Sharing) headers to support Cross-site HTTP requests

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

Il y a quelque temps, j'ai rencontré ce problème et je l'ai donc fait pour permettre à CORS dans mon application nodejs:

D'abord vous devez installercors en utilisant la commande ci-dessous:

npm install cors --save

Maintenant ajoutez le code suivant dans le fichier de démarrage de votre application tel que (app.js or server.js)

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
}));

require('./router/index')(app);
9
Shubham Verma

Cela fonctionne pour moi, car c’est une implémentation facile dans les itinéraires, en utilisant meanjs et son fonctionnement, safari, chrome, etc.

app.route('/footer-contact-form').post(emailer.sendFooterMail).options(function(req,res,next){ 
        res.header('Access-Control-Allow-Origin', '*'); 
        res.header('Access-Control-Allow-Methods', 'GET, POST');
        res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
        return res.send(200);

    });
9
Kiko Seijo

Si vous voulez le rendre spécifique au contrôleur, vous pouvez utiliser:

res.setHeader('X-Frame-Options', 'ALLOWALL');
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST, GET');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');

Veuillez noter que cela autorisera également les iframes.

6
Koray Gocmen

Ma solution la plus simple avec Express 4.2.0 (EDIT: ne semble pas fonctionner en 4.3.0) était la suivante:

function supportCrossOriginScript(req, res, next) {
    res.status(200);
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Content-Type");

    // res.header("Access-Control-Allow-Headers", "Origin");
    // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    // res.header("Access-Control-Allow-Methods","POST, OPTIONS");
    // res.header("Access-Control-Allow-Methods","POST, GET, OPTIONS, DELETE, PUT, HEAD");
    // res.header("Access-Control-Max-Age","1728000");
    next();
}

// Support CORS
app.options('/result', supportCrossOriginScript);

app.post('/result', supportCrossOriginScript, function(req, res) {
    res.send('received');
    // do stuff with req
});

Je suppose que faire app.all('/result', ...) fonctionnerait aussi ...

3
Pat

Peut faire référence au code ci-dessous pour la même chose. Source: Academind/node-reposful-api

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

//acts as a middleware
//to handle CORS Errors
app.use((req, res, next) => { //doesn't send response just adjusts it
    res.header("Access-Control-Allow-Origin", "*") //* to give access to any Origin
    res.header(
        "Access-Control-Allow-Headers",
        "Origin, X-Requested-With, Content-Type, Accept, Authorization" //to give access to all the headers provided
    );
    if(req.method === 'OPTIONS'){
        res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET'); //to give access to all the methods provided
        return res.status(200).json({});
    }
    next(); //so that other routes can take over
})
3
Gadhia Reema

Dans mon index.js j'ai ajouté:

app.use((req, res, next) => {
   res.header("Access-Control-Allow-Origin", "*");
   res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
   res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
   next();
}) 
3
Balaj Khan

Utiliser Express Middleware me convient parfaitement. Si vous utilisez déjà Express, ajoutez simplement les règles suivantes du middleware. Il devrait commencer à fonctionner.

app.all("/api/*", function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With");
  res.header("Access-Control-Allow-Methods", "GET, PUT, POST");
  return next();
});

app.all("/api/*", function(req, res, next) {
  if (req.method.toLowerCase() !== "options") {
    return next();
  }
  return res.send(204);
});

référence

2
Ishan Patel

Outre ce que d'autres ont dit, n'oubliez pas que, sauf si vous utilisez nodemon, vous devrez redémarrer votre serveur de noeud pour que les modifications prennent effet!

Personnellement, j’avais rafraîchi mon navigateur par habitude, en oubliant qu’il s’agissait d’un code côté serveur.

2
camjocotem

Ci-dessous a fonctionné pour moi, j'espère que cela aidera quelqu'un!

const express = require('express');
const cors = require('cors');
let app = express();

app.use(cors({ Origin: true }));

Référence obtenue de https://expressjs.com/en/resources/middleware/cors.html#configuring-cors

1
Vatsal Shah

Je trouvais extrêmement facile de faire cela avec le paquet de demande npm ( https://www.npmjs.com/package/request )

Ensuite, j'ai basé ma solution sur ce post http://blog.javascripting.com/2015/01/17/dont-hassle-with-cors/

'use strict'

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

let proxyConfig = {
    url : {
        base: 'http://servertoreach.com?id=',
    }
}

/* setting up and configuring node express server for the application */
let server = express();
server.set('port', 3000);


/* methods forwarded to the servertoreach proxy  */
server.use('/somethingElse', function(req, res)
{
    let url = proxyConfig.url.base + req.query.id;
    req.pipe(request(url)).pipe(res);
});


/* start the server */
server.listen(server.get('port'), function() {
    console.log('express server with a proxy listening on port ' + server.get('port'));
});
1
melvinv

Ceci est similaire à la réponse de Pat avec la différence que je termine avec res.sendStatus (200); au lieu de next ();

Le code interceptera toutes les requêtes du type de méthode OPTIONS et renverra les en-têtes access-control-control.

app.options('/*', (req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
    res.sendStatus(200);
});

Le code accepte les CORS de toutes origines, comme demandé dans la question. Cependant, il serait préférable de remplacer * par une origine spécifique, à savoir http: // localhost: 808 , afin d’empêcher toute utilisation abusive.

Puisque nous utilisons la méthode app.options au lieu de la méthode app.use, nous n'avons pas besoin de faire cette vérification:

req.method === 'OPTIONS'

que nous pouvons voir dans certaines des autres réponses.

J'ai trouvé la réponse ici: http://johnzhang.io/options-request-in-express .

1
Swoot

en utilisant nodejs sans bibliothèques externes/externes, j’ai utilisé la méthode ci-dessous dans mon fichier server.js. Les parties clés ici obtiennent l’origine de l’en-tête de la demande, puis l’autorisent dans la réponse du serveur. Nous pouvons alors définir l’en-tête qui sera renvoyé, y compris l’origine autorisée si une correspondance est trouvée.

    **const Origin = req.headers.Origin;**

      let decoder = new StringDecoder('utf-8');
      let buffer = '';
      req.on('data', function (data) {
        buffer += decoder.write(data);
      });
      req.on('end', function () {
        buffer += decoder.end();

        let chosenHandler = typeof (server.router[trimmedPath]) !== 'undefined' ? server.router[trimmedPath] : handlers.notFound;

const data = { ....data object vars}

// should be wrapped in try catch block
      chosenHandler(data, function (statusCode, payload, contentType) {
        server.processHandlerResponse(res, method, trimmedPath, statusCode, payload, contentType, **Origin**);


server.processHandlerResponse = function (res, method, trimmedPath, statusCode, payload, contentType, Origin) {
  contentType = typeof (contentType) == 'string' ? contentType : 'json';

  statusCode = typeof (statusCode) == 'number' ? statusCode : 200;

  let payloadString = '';
  if (contentType == 'json') {
    res.setHeader('Content-Type', 'application/json');

    const allowedOrigins = ['https://www.domain1.com', 'https://someotherdomain','https://yetanotherdomain',
    ...// as many as you need
  ];
    **if (allowedOrigins.indexOf(Origin) > -1) {
        res.setHeader('Access-Control-Allow-Origin', Origin);
    }**
    payload = typeof (payload) == 'object' ? payload : {};
    payloadString = JSON.stringify(payload);
  }

... //  if (other content type) ...rinse and repeat..
0
Johnathan Enslin

Si j'étais vous @OP, je changerais mon paradigme de programmation.

en supposant que vous obtenez ces CORS bloqués parce que vous faites des demandes à localhost ou quelque chose de similaire.

Finalement, si vous allez déployer des optoins de production comme Google Cloud Platform ou Heroku ou, vous n’aurez plus à vous soucier des CORS comme autoriser Origin ou peu importe lorsqu’ils sont en production.

par conséquent, lors du test du serveur, utilisez simplement postman et vous ne serez pas bloqué par CORS. Par la suite, déployez votre serveur et travaillez ensuite sur votre client.

0
Maddocks

Le code ci-dessous fonctionnera, mais installez d’abord cors:

npm install --save cors

Ensuite:

module.exports = function(app) { 
var express = require("express");
var cors = require('cors');
var router = express.Router();
app.use(cors());

app.post("/movies",cors(), function(req, res) { 
res.send("test");
});
0
BCool

J'ai utilisé les étapes suivantes pour mon application Web et j'ai eu du succès:

Ajoutez le paquet cors au courrier express:

npm install cors --save

Ajoutez les lignes suivantes après la configuration de bodyParser. J'ai eu quelques problèmes en ajoutant avant bodyParser:

 // enable cors to the server
const corsOpt = {
    Origin: process.env.CORS_ALLOW_Origin || '*', // this work well to configure Origin url in the server
    methods: ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS'], // to works well with web app, OPTIONS is required
    allowedHeaders: ['Content-Type', 'Authorization'] // allow json and token in the headers
};
app.use(cors(corsOpt)); // cors for all the routes of the application
app.options('*', cors(corsOpt)); // automatic cors gen for HTTP verbs in all routes, This can be redundant but I kept to be sure that will always work.
0
Ângelo Polotto
const express = require("express");
const router = express.Router();
const app = express();
const cors = require("cors"); 



const options = {
  Origin: true,
  "Access-Control-Allow-Credentials": true,

  "Access-Control-Allow-Origin": true,
  "Access-Control-Allow-Headers": true,
  "Access-Control-Expose-Headers": true
};


app.use(cors(options));
router.get("/", cors(options), (req, res) => {
  res.render("index", { title: "Express" });
});

module.exports = router;

Pour GOOGLE CHROME, vous devez ajouter l'extension "Allow-Control-Allow-Origin".

L'en-tête Access-Control-Allow-Origin (en-tête de réponse) indique si une ressource peut être SHARED en renvoyant la valeur de l'en-tête de demande Origin. L'en-tête Access-Control-Allow-Origin ouvre une porte pour un accès croisé

Access-Control-Allow-Credentials (en-tête de réponse): true est utilisé pour indiquer que le client est autorisé à utiliser des informations d'identification. Par défaut, les réponses aux demandes authentifiées ne peuvent pas être lues par le script client. Ainsi, vous pouvez accéder à la réponse. De plus, CORS n'inclut pas de cookies dans les requêtes cross-origin, ce qui peut entraîner une classe de vulnérabilités appelée falsification de requête cross-site ou CSRF. Afin de réduire le risque de vulnérabilités CSRF dans CORS, CORS exige que le serveur et le client reconnaissent qu'il est correct d'inclure des cookies sur les demandes.

Les en-têtes de contrôle d'accès (en-tête de réponse) indiquent les en-têtes pouvant être exposés en toute sécurité. Une liste des en-têtes de la réponse pouvant être lus. Par défaut, seuls les 6 en-têtes de réponse simples sont exposés: Contrôle du cache, Langage du contenu, Type de contenu, Expire, Dernière modification, Pragma

Les en-têtes de demande de contrôle d'accès (en-tête de demande) indiquent quels en-têtes HTTP peuvent être utilisés lors de la demande réelle.

Origin = true (en-tête de la demande) reflète l'origine de la demande. Si c'est faux, Cors sera désactivé.

0
Yilmaz

Dans TypeScript, si vous souhaitez utiliser le package node.js cors

/**
* app.ts
* If you use the cors library
*/

import * as express from "express";
[...]
import * as cors from 'cors';

class App {
   public express: express.Application;

   constructor() {
       this.express = express();
       [..]
       this.handleCORSErrors();
   }

   private handleCORSErrors(): any {
       const corsOptions: cors.CorsOptions = {
           Origin: 'http://example.com',
           optionsSuccessStatus: 200
       };
       this.express.use(cors(corsOptions));
   }
}

export default new App().express;

Si vous ne souhaitez pas utiliser de bibliothèques tierces pour la gestion des erreurs cors, vous devez modifier la méthode handleCORSErrors ().

/**
* app.ts
* If you do not use the cors library
*/

import * as express from "express";
[...]

class App {
   public express: express.Application;

   constructor() {
       this.express = express();
       [..]
       this.handleCORSErrors();
   }

   private handleCORSErrors(): any {
       this.express.use((req, res, next) => {
           res.header("Access-Control-Allow-Origin", "*");
           res.header(
               "Access-Control-ALlow-Headers",
               "Origin, X-Requested-With, Content-Type, Accept, Authorization"
           );
           if (req.method === "OPTIONS") {
               res.header(
                   "Access-Control-Allow-Methods",
                   "PUT, POST, PATCH, GET, DELETE"
               );
               return res.status(200).json({});
           } 
           next(); // send the request to the next middleware
       });
    }
}

export default new App().express;

Pour utiliser le fichier app.ts

/**
* server.ts
*/
import * as http from "http";
import app from "./app";

const server: http.Server = http.createServer(app);

const PORT: any = process.env.PORT || 3000;
server.listen(PORT);
0
overcomer

Nous pouvons éviter CORS et transférer les demandes à l'autre serveur à la place:

// config:
var public_folder = __dirname + '/public'
var apiServerHost = 'http://other.server'

// code:
console.log("starting server...");

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

// serve static files
app.use(express.static(public_folder));

// if not found, serve from another server
app.use(function(req, res) {
    var url = apiServerHost + req.url;
    req.pipe(request(url)).pipe(res);
});

app.listen(80, function(){
    console.log("server ready");
});
0
Bernardo Ramos

L’approche la plus simple consiste à installer le module cors dans votre projet en utilisant:

npm i --save cors

Ensuite, dans votre fichier de serveur, importez-le en utilisant les éléments suivants:

import cors from 'cors';

Ensuite, utilisez-le simplement comme middleware comme ceci:

app.use(cors());

J'espère que cela t'aides!

0
Harshit Agarwal