Socket.io + Node.js Запрос на перекрестный запрос заблокирован

Я использую node и socket.io для написания приложения чата. Он отлично работает на Chrome, но mozilla дает ошибку, чтобы разрешить запросы Cross-Origin.

Запрос на перекрестный запрос заблокирован: политика одинакового происхождения запрещает чтение удаленного ресурса http://waleedahmad.kd.io:3000/socket.io/?EIO=2&transport=polling&t=1401964309289-2&sid=1OyDavRDf4WErI-VAAAI. Это можно устранить, переместив ресурс в тот же домен или включив CORS.

Здесь мой код для запуска сервера node.

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

На стороне клиента.

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

Script на странице HTML.

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

Я также использую файл .htaccess в корневом каталоге приложения. (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"

Ответы

Ответ 1

Простое исправление на стороне сервера

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

или

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

или

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

* один не работает, что заставило меня кроличьи дыры.

Ответ 2

Вы можете попробовать установить опцию origins на стороне сервера, чтобы разрешить запросы с кросс-началом:

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

Здесь http://yourdomain.com:80 - это источник, из которого вы хотите разрешить запросы.

Подробнее о origins формате здесь можно прочитать здесь

Ответ 3

Я пытался выше, и у меня ничего не получалось. Следующий код взят из документации по socket.io, и это сработало.

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

Ответ 4

Это может быть проблема с сертификацией с Firefox, не обязательно что-то не так с вашим CORS. Запрос Firefox CORS, дающий запрос на перекрестный запрос заблокирован, несмотря на заголовки

Я столкнулся с тем же вопросом, что и Socketio и Nodejs, бросающие ошибку CORS в Firefox. У меня были сертификаты для *.myNodeSite.com, но я ссылался на IP-адрес LAN 192.168.1.10 для Nodejs. (IP-адрес WAN также может вызывать ту же ошибку.) Поскольку Cert не соответствовал ссылке на IP-адрес, Firefox выбросил эту ошибку.

Ответ 5

Прочитав много статей на StakOverflow и других форумах, я нашел для себя рабочее решение. Это решение для работы без Express.

вот предпосылки.


СТОРОНА СЕРВЕРА

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

});

СТОРОНА КЛИЕНТА

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

Ответ 6

Я использую v2.1.0 и ни один из вышеупомянутых ответов не работал для меня. Это сделал, хотя:

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

Ответ 7

Если ничего не работает Запустите это в окне запуска окна + г

chrome.exe --user-data-dir = "C: /Chrome dev session" --disable-web-security

Моя проблема решена с помощью этого метода, установка плагина cors работает для php, apis rest rest узла, но в случае socket.io, когда я включаю сокет cors перестал работать. я работаю как на разных портах

localhost: 3001 и нг на localhost: 4200

UPDATE-- я сейчас использую пакет npm cors, и он работает как шарм. Нет проблем с socket.io.

Добавьте это так

var express = require('express');
var app = express();
var http = require('http').Server(app);
const cors = require('cors');
var bodyParser   = require('body-parser');
app.use(cors());
app.options('*', cors());

const auth = require('./routes/auth');

 const port = 3004;
http.listen(port, () => {
  console.log( 'running http at port ${port}');
});

Ответ 8

Хорошо, у меня были некоторые проблемы, заставляющие это работать с использованием самоподписанного сертификата для тестирования, поэтому я собираюсь скопировать мою установку, которая работала для меня. Если вы не используете самозаверяющий сертификат, у вас, вероятно, не будет этих проблем, надеюсь!

Для начала, в зависимости от вашего браузера Firefox или Chrome, у вас могут быть разные проблемы, и я объясню через минуту.

Сначала установка:

клиент

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

сервер

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

Для разработки, параметры, используемые на стороне клиента, хорошо работают, вы бы хотели вариант:

 rejectUnauthorized: false

Вы, скорее всего, захотите установить значение "истина"

Следующее, что нужно сделать, если это самозаверяющий сертификат, вам нужно посетить свой сервер на отдельной странице/вкладке и принять сертификат или импортировать его в свой браузер.

Для Firefox я продолжал получать ошибку

MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT

Решением для меня было добавить следующие параметры и принять сертификат на другой странице/вкладке.

{ 
rejectUnauthorized: false
} 

В Chrome мне пришлось открыть еще одну страницу и принять сертификат, но после этого все работало без необходимости добавлять какие-либо параметры.

Надеюсь это поможет.

Рекомендации:

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

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