Socket.io + Node.js Ursprungsübergreifende Anforderung blockiert

77

Ich verwende node und socket.io, um eine Chat-Anwendung zu schreiben. Es funktioniert gut in Chrome, aber Mozilla gibt einen Fehler aus, um die Cross-Origin-Anfragen zu aktivieren.

Ursprungsübergreifende Anforderung blockiert: Die gleiche Ursprungsrichtlinie verbietet das Lesen der Remote-Ressource unter http://waleedahmad.kd.io:3000/socket.io/?EIO=2&transport=polling&t=1401964309289-2&sid=1OyDavRDf4WErI-VAAAI . Dies kann behoben werden, indem die Ressource in dieselbe Domäne verschoben oder CORS aktiviert wird.

Hier ist mein Code zum Starten des Knotenservers.

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

Auf der Client-Seite.

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

Skript-Tag auf der HTML-Seite.

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

Ich verwende auch die .htaccess-Datei im App-Stammverzeichnis. (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"
Waleed Ahmad
quelle
1
Hast du das jemals zum Laufen gebracht? Wenn ja, was war Ihre Lösung?
elynnaie

Antworten:

92

Einfache serverseitige Korrektur

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

oder

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

oder

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

* allein funktioniert nicht, was mich in Kaninchenlöcher geführt hat.

Jason Sebring
quelle
5
Ich benutze die neueste Version und es ist nicht, es gibt mir Verbindung verweigert Fehler
Spieler
@gamer arbeitet vielleicht alle ersten Prinzipien durch und blockiert dann zum Beispiel. Blockiert meine Firewall den Port? Kann ich meinen Server usw. usw. anpingen?
Jason Sebring
Du bist ein Genie. Dies ist die beste Lösung mit Express!
abelabbesnabi
59

Ich benutze v2.1.0und keine der oben genannten Antworten hat für mich funktioniert. Dies tat jedoch:

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);
Kwabena Berko
quelle
1
Ich möchte verstehen, warum dies über io.origin (" : ") funktioniert. Das macht keinen Sinn. Ich habe sogar versucht, dies mit Ursprungshandlern von socket.io zu überschreiben. 4 und socket.io-client 2.2.0 mit socket.io-adapter-mongodb 0.0.2
The Bumpaster
1
Ich bin so dankbar, dass ich diesen Beitrag gefunden habe. Ich habe heute 5-6 Stunden damit verbracht, CORS auf meinem Socket-Server zu aktivieren. Ich habe buchstäblich jede einzelne Methode ausprobiert, die ich im Stackoverflow finden konnte. Dies ist die einzige Methode, die bei mir funktioniert hat. Ich verstehe nicht, warum io.origin (":") auch in diesem Fall nicht funktioniert hat. Ich habe in der Vergangenheit andere Socket-Server gebaut und bin nie auf Probleme gestoßen. Wenn jemand eine Theorie hat, würde ich sie gerne hören. Trotzdem vielen Dank für das Teilen!
Octavemirbeau
33

Sie können versuchen, die originsOption auf der Serverseite festzulegen, um Ursprungsübergreifende Anforderungen zuzulassen:

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

Hier http://yourdomain.com:80ist der Ursprung, von dem Sie Anfragen zulassen möchten.

Weitere Informationen zum originsFormat finden Sie hier

Oleg
quelle
12

Für alle, die hier nach neuem Socket.io (3.x) suchen, sind die Migrationsdokumente ziemlich hilfreich.

Insbesondere dieses Snippet:

const io = require("socket.io")(httpServer, {
  cors: {
    origin: "https://example.com",
    methods: ["GET", "POST"],
    allowedHeaders: ["my-custom-header"],
    credentials: true
  }
});
Brett Klassen
quelle
9

Ich habe es oben versucht und nichts hat bei mir funktioniert. Der folgende Code stammt aus der Dokumentation zu socket.io und hat funktioniert.

io.origins((origin, callback) => {
  if (origin !== 'https://foo.example.com') {
      return callback('origin not allowed', false);
  }
  callback(null, true);
});
abe.hd
quelle
4

Nachdem ich viele Subjetcs in StakOverflow und anderen Foren gelesen hatte, fand ich die funktionierende Lösung für mich. Diese Lösung ist für das Arbeiten ohne Express vorgesehen .

Hier sind die Voraussetzungen.


SERVER SEITE

// 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

});

KUNDENSEITE

<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>
Meloman
quelle
Dies ist eines der klarsten Beispiele für einen NodeJS-Server mit Socket.io-Integration. upvoted
Nactus
4

Beim Erstellen einer Chat-App mit socket.io und node.js & React tritt ein Problem auf. Auch dieses Problem ist für den Firefox-Browser nicht platzsparend. Ich habe das gleiche Problem auch in Edge & Chrome.

"Ursprungsübergreifende Anfrage ist blockiert und wird von einigen anderen Ressourcen verwendet ..."

Dann lade ich cors in das Projektverzeichnis herunter und lege es wie folgt in die Serverdatei index.js: Zum Herunterladen geben Sie einfach den Befehl mit node.js ein:

npm install cors

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

Dadurch kann CORS von verschiedenen Ressourcen in den Dateien verwendet werden und es kann eine Cross-Origin-Anfrage im Browser gestellt werden.

akshay_sushir
quelle
3

Okay, ich hatte einige Probleme damit, dass dies mit einem selbstsignierten Zertifikat zum Testen funktioniert, also werde ich mein Setup kopieren, das für mich funktioniert hat. Wenn Sie kein selbstsigniertes Zertifikat verwenden, werden Sie diese Probleme wahrscheinlich nicht haben, hoffentlich!

Abhängig von Ihrem Browser Firefox oder Chrome können verschiedene Probleme auftreten, die ich Ihnen gleich erläutern werde.

Zuerst das Setup:

Klient

// 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>

Server

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

Für die Entwicklung sind die auf der Client-Seite verwendeten Optionen in der Produktion in Ordnung. Sie möchten die Option:

 rejectUnauthorized: false

Sie möchten höchstwahrscheinlich auf "wahr" setzen.

Wenn es sich um ein selbstsigniertes Zertifikat handelt, müssen Sie Ihren Server auf einer separaten Seite / Registerkarte besuchen und das Zertifikat akzeptieren oder in Ihren Browser importieren.

Für Firefox bekam ich immer wieder den Fehler

MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT

Die Lösung für mich bestand darin, die folgenden Optionen hinzuzufügen und das Zertifikat auf einer anderen Seite / Registerkarte zu akzeptieren.

{ 
rejectUnauthorized: false
} 

In Chrome musste ich eine andere Seite öffnen und das Zertifikat akzeptieren, aber danach funktionierte alles einwandfrei, ohne dass Optionen hinzugefügt werden mussten.

Hoffe das hilft.

Verweise:

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

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

Kyle Coots
quelle
3

Wenn Sie io.set not a functionoder erhalten io.origins not a function, können Sie eine solche Notation versuchen:

import express from 'express';
import { Server } from 'socket.io';
const app = express();
const server = app.listen(3000);
const io = new Server(server, { cors: { origin: '*' } });
Олександр Данильченко
quelle
2

Dies könnte ein Zertifizierungsproblem mit Firefox sein, nicht unbedingt etwas, das mit Ihrem CORS nicht stimmt. Firefox CORS-Anfrage mit 'Cross-Origin Request Blocked' trotz Headern

Ich hatte genau das gleiche Problem mit Socketio und Nodejs, die in Firefox einen CORS-Fehler auslösten. Ich hatte Zertifikate für * .myNodeSite.com, bezog mich jedoch auf die LAN-IP-Adresse 192.168.1.10 für Nodejs. (Die WAN-IP-Adresse kann ebenfalls denselben Fehler auslösen.) Da das Zertifikat nicht mit der IP-Adressreferenz übereinstimmt, hat Firefox diesen Fehler ausgegeben.

Ryan Smith
quelle
0

Ich hatte das gleiche Problem und jede Lösung funktionierte für mich.

Die Ursache war, dass ich allowRequest verwende, um die Verbindung mithilfe eines Tokens zu akzeptieren oder abzulehnen, das ich in einem Abfrageparameter übergebe.

Ich habe einen Tippfehler im Namen des Abfrageparameters auf der Clientseite, daher wurde die Verbindung immer abgelehnt, aber der Browser hat sich über cors beschwert ...

Sobald ich den Tippfehler behoben habe, funktionierte er wie erwartet und ich muss nichts mehr verwenden. Die globalen Express-Cors-Einstellungen reichen aus.

Wenn also etwas für Sie funktioniert und Sie allowRequest verwenden, überprüfen Sie, ob diese Funktion ordnungsgemäß funktioniert, da die von ihr ausgelösten Fehler im Browser als cors-Fehler angezeigt werden. Es sei denn, Sie fügen dort die cors-Header manuell hinzu, wenn Sie die Verbindung ablehnen möchten, denke ich.

Pykiss
quelle