web-dev-qa-db-fra.com

Socket.io + Node.js Demande d'origine croisée bloquée

J'utilise node et socket.io pour écrire une application de discussion. Cela fonctionne bien sous Chrome, mais mozilla génère une erreur pour activer les requêtes d'origine croisée.

Demande d'origine croisée bloquée: la règle de même origine interdit la lecture de la ressource distante sur http://waleedahmad.kd.io:3000/socket.io/?EIO=2&transport=polling&t=1401964309289-2&sid=1OyDavRDf4WErI-VAAAAI . Cela peut être corrigé en déplaçant la ressource dans le même domaine ou en activant CORS.

Voici mon code pour démarrer le serveur de noeud.

var express = require('express'),
    app = express(), 
    server = require('http').createServer(app),
    io = require('socket.io').listen(server),
    path = require('path');
server.listen(3000);

app.get('/', function(req, res) {
    res.sendfile(__dirname + '/public/index.html');
});

Du côté du client.

var socket = io.connect('//waleedahmad.kd.io:3000/');

Balise de script sur la page HTML.

<script type="text/javascript" src="//waleedahmad.kd.io:3000/socket.io/socket.io.js"></script>

J'utilise également le fichier .htaccess dans le répertoire racine de l'application. (waleedahmad.kd.io/node).

Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "Origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
37
Waleed Ahmad

Solution simple côté serveur

var io = require('socket.io')(server, { origins: '*:*'});

ou

io.set('origins', '*:*');

ou

io.origins('*:*') // for latest version

* seul ne fonctionne pas, ce qui m'a fait descendre dans des trous de lapin.

48
Jason Sebring

Vous pouvez essayer de définir l'option origins sur le serveur pour autoriser les requêtes inter-origines:

io.set('origins', 'http://yourdomain.com:80');

Ici, http://yourdomain.com:80 correspond à l'origine à partir de laquelle vous souhaitez autoriser les demandes.

Vous pouvez en savoir plus sur le format originsici

25
Oleg

J'ai essayé ci-dessus et rien n'a fonctionné pour moi. Le code suivant provient de documentation de socket.io et cela a fonctionné.

io.origins((Origin, callback) => {
  if (Origin !== 'https://foo.example.com') {
      return callback('Origin not allowed', false);
  }
  callback(null, true);
});
3

Cela pourrait être un problème de certification avec Firefox, pas nécessairement quelque chose qui cloche avec votre CORS. Demande Firefox CORS indiquant 'Requête d'origines croisées bloquée' malgré les en-têtes

Je rencontrais exactement le même problème avec Socketio et Nodejs en lançant une erreur CORS dans Firefox. J'avais Certs pour * .myNodeSite.com, mais je faisais référence à l'adresse IP du réseau local 192.168.1.10 pour Nodejs. (L'adresse IP WAN peut également générer la même erreur.) Le certificat ne correspondant pas à la référence de l'adresse IP, Firefox a renvoyé cette erreur. 

2
Ryan Smith

Après avoir lu beaucoup de sujets sur StakOverflow et d’autres forums, j’ai trouvé la solution la plus adaptée. Cette solution est pour travailler sans Express.

voici les prérequis.


DU CÔTÉ SERVEUR

// DEPENDENCIES
var fs       = require('fs'),
    winston  = require('winston'),
    path     = require('path');


// LOGS
const logger = winston.createLogger({
    level     : 'info',
    format    : winston.format.json(),
    transports: [
        new winston.transports.Console({ level: 'debug' }),
        new winston.transports.File({ filename: 'err.log', level: 'err' }),
        new winston.transports.File({ filename: 'combined.log' })
    ]
});


// CONSTANTS
const Port          = 9000,
      certsPath     = '/etc/letsencrypt/live/my.domain.com/';


// STARTING HTTPS SERVER 
var server = require('https').createServer({
    key:                fs.readFileSync(certsPath + 'privkey.pem'), 
    cert:               fs.readFileSync(certsPath + 'cert.pem'), 
    ca:                 fs.readFileSync(certsPath + 'chain.pem'), 
    requestCert:        false, 
    rejectUnauthorized: false 
},
(req, res) => {

    var filePath = '.' + req.url;
    logger.info('FILE ASKED : ' + filePath);

    // Default page for visitor calling directly URL
    if (filePath == './')
        filePath = './index.html';

    var extname = path.extname(filePath);
    var contentType = 'text/html';

    switch (extname) {
        case '.js':
            contentType = 'text/javascript';
            break;
        case '.css':
            contentType = 'text/css';
            break;
        case '.json':
            contentType = 'application/json';
            break;
        case '.png':
            contentType = 'image/png';
            break;      
        case '.jpg':
            contentType = 'image/jpg';
            break;
        case '.wav':
            contentType = 'audio/wav';
            break;
    }

    var headers = {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'OPTIONS, POST, GET',
        'Access-Control-Max-Age': 2592000, // 30 days
        'Content-Type': contentType
    };

    fs.readFile(filePath, function(err, content) {
        if (err) {
            if(err.code == 'ENOENT'){
                fs.readFile('./errpages/404.html', function(err, content) {
                    res.writeHead(404, headers);
                    res.end(content, 'utf-8');
                });
            }
            else {
                fs.readFile('./errpages/500.html', function(err, content) {
                    res.writeHead(500, headers);
                    res.end(content, 'utf-8');
                });
            }
        }
        else {
            res.writeHead(200, headers);
            res.end(content, 'utf-8');
        }
    });

    if (req.method === 'OPTIONS') {
        res.writeHead(204, headers);
        res.end();
    }

}).listen(port); 


//OPENING SOCKET
var io = require('socket.io')(server).on('connection', function(s) {

    logger.info("SERVER > Socket opened from client");

    //... your code here

});

CÔTÉ CLIENT

<script src="https://my.domain.com:port/js/socket.io.js"></script>
<script>
    $(document).ready(function() {

        $.socket = io.connect('https://my.domain.com:port', {
            secure: true // for SSL
        });

        //... your code here

    });
</script>
1
Meloman

Bon, j’ai eu quelques problèmes à le faire fonctionner en utilisant un certificat auto-signé pour les tests, donc je vais copier ma configuration qui a fonctionné pour moi. Si vous n'utilisez pas de certificat auto-signé, vous n'aurez probablement pas ces problèmes, espérons-le!

Pour commencer, selon votre navigateur Firefox ou Chrome, vous pouvez avoir des problèmes différents et je vais vous expliquer dans une minute. 

D'abord la configuration:

Client

// May need to load the client script from a Absolute Path
<script src="https://www.YOURDOMAIN.com/node/node_modules/socket.io-client/dist/socket.io.js"></script>
<script>
var options = {
          rememberUpgrade:true,
          transports: ['websocket'],
          secure:true, 
          rejectUnauthorized: false
              }
var socket = io.connect('https://www.YOURDOMAIN.com:PORT', options);

// Rest of your code here
</script>

Serveur

var fs = require('fs');

var options = {
  key: fs.readFileSync('/path/to/your/file.pem'),
  cert: fs.readFileSync('/path/to/your/file.crt'),

};
var origins = 'https://www.YOURDOMAIN.com:*';
var app = require('https').createServer(options,function(req,res){

    // Set CORS headers
    res.setHeader('Access-Control-Allow-Origin', 'https://www.YOURDOMAIN.com:*');
    res.setHeader('Access-Control-Request-Method', '*');
    res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
    res.setHeader('Access-Control-Allow-Headers', '*');
    if ( req.method === 'OPTIONS' || req.method === 'GET' ) {
        res.writeHead(200);
        res.end();
        return;
            }

});

var io = require('socket.io')(app);

app.listen(PORT);

Pour le développement, les options utilisées côté client sont acceptables en production. Vous voudriez l'option:

 rejectUnauthorized: false

Vous voudriez probablement plus que réglé sur "true"

La prochaine chose à faire est que s’il s’agit d’un certificat auto-signé, vous devrez classer votre serveur dans une page/un onglet séparé et accepter le certificat ou l’importer dans votre navigateur. 

Pour Firefox, je continuais à avoir l'erreur 

MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT

La solution pour moi était d’ajouter les options suivantes et d’accepter le certificat dans une page/un onglet différent.

{ 
rejectUnauthorized: false
} 

Sous Chrome, je devais ouvrir une autre page et accepter le certificat, mais après cela, tout fonctionnait sans avoir à ajouter d'options.

J'espère que cela t'aides.

Références:

https://github.com/theturtle32/WebSocket-Node/issues/259

https://github.com/socketio/engine.io-client#methods

0
toystory

Si rien ne fonctionne Exécutez ceci dans la fenêtre d'exécution Window + r

chrome.exe --user-data-dir = "C:/session de développement Chrome" --disable-web-security

mon problème résolu en utilisant cette méthode, l’installation du plugin cors fonctionne pour php, le reste du noeud apis mais en cas de socket.io quand j’active le socket cors a cessé de fonctionner .

localhost: 3001, et sur localhost: 4200

0
Aklesh Singh

J'utilise v2.1.0 et aucune des réponses ci-dessus n'a fonctionné pour moi. Ceci cependant:

import express from "express";
import http from "http";

const app = express();
const server = http.createServer(app);

const sio = require("socket.io")(server, {
    handlePreflightRequest: (req, res) => {
        const headers = {
            "Access-Control-Allow-Headers": "Content-Type, Authorization",
            "Access-Control-Allow-Origin": req.headers.Origin //or the specific Origin you want to give access to,
            "Access-Control-Allow-Credentials": true
        };
        res.writeHead(200, headers);
        res.end();
    }
});

sio.on("connection", () => {
    console.log("Connected!");
});

server.listen(3000);
0
Kwabena Berko