Socket.io + Node.js Запит перехресного походження заблоковано


90

Я використовую node та socket.io для написання програми чату. Він чудово працює в Chrome, але mozilla видає помилку, щоб увімкнути запити на перехресне походження.

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

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

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

Тег сценарію на 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
Ви коли-небудь працювали над цим? Якщо так, то яким було ваше рішення?
elynnaie

Відповіді:


128

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

Примітка: НЕ ВИКОРИСТОВУЙТЕ пакет "socketio" ... замість цього використовуйте "socket.io". "socketio" застарілий. Здається, деякі користувачі використовують неправильний пакет.

socket.io v3

документи: https://socket.io/docs/v3/handling-cors/

опції cors: https://www.npmjs.com/package/cors

const io = require('socket.io')(server, {
  cors: {
    origin: '*',
  }
});

socket.io <v3

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

або

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

або

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

* сам по собі не працює, що забрало мене в кролячі нори.


7
Я використовую останню версію, і це не так, її повідомлення про підключення відмовило в помилці
геймер

@gamer, можливо, працює над усіма першими принципами, а потім піднімається, наприклад, чи мій брандмауер блокує порт? Чи можу я пінгувати свій сервер і т. Д.
Джейсон Себрінг,

Ви геній. Це найкраще рішення з Express!
abelabbesnabi

2
З v3.x, будь ласка, зверніться до цього ( socket.io/docs/v3/handling-cors ) та цього ( github.com/expressjs/cors#configuration-options ) посилання. `` var io = require ('socket.io') (http, {'cors': {'methods': ['GET', 'PATCH', 'POST', 'PUT'], 'origin': true // приймаємо з будь-якого домену}}); ``
ві,

59

Я використовую, 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);

1
Я хотів би зрозуміти, чому це працює над io.origin (" : ") Немає сенсу, я навіть намагався перевизначити це за допомогою обробників походження з socket.io, зазначивши, що працював крім цього .. Я використовую socket.io 1.7. 4 і socket.io-client 2.2.0 з socket.io-adapter-mongodb 0.0.2
The Bumpaster

1
Я дуже вдячний, що знайшов цю публікацію, сьогодні витратив 5-6 годин, щоб спробувати увімкнути CORS на своєму сокет-сервері. Я буквально перепробував кожен метод, який міг знайти на stackoverflow. Це єдиний метод, який працював у мене. Я не розумію, чому io.origin (":") також не спрацював у цьому випадку. Раніше я будував інші сервери сокетів і ніколи не стикався з проблемами. Якщо хтось має теорію, я хотів би її почути. У будь-якому випадку велике спасибі, що поділилися цим!
octavemirbeau

34

Ви можете спробувати встановити originsпараметр на стороні сервера, щоб дозволити запити на перехресне походження:

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

Ось http://yourdomain.com:80джерело, з якого ви хочете дозволити запити.

Детальніше про originsформат ви можете прочитати тут


20

Для тих, хто шукає тут новий Socket.io (3.x), міграційні документи є досить корисними.

Зокрема цей фрагмент:

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

ідеально! Тепер мій сокет розбивається на запит POST і каже, що це погане рукостискання мого клієнта vue socket.io. Але я бачу цю нову помилку як прогрес. Дуже дякую!
frlzjosh,

9

Я спробував вище, і мені нічого не вдалося. Наступний код з документації socket.io, і він працював.

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

6

Я просто хотів сказати, що, спробувавши купу речей, те, що вирішило мою проблему CORS, було просто використання старішої версії socket.io (версія 2.2.0). Мій файл package.json тепер виглядає так:

{
  "name": "current-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "devStart": "nodemon server.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "socket.io": "^2.2.0"
  },
  "devDependencies": {
    "nodemon": "^1.19.0"
  }
}


Якщо виконати npm installз цим, ви можете виявити, що проблема CORS зникає при спробі використовувати socket.io. Принаймні, це спрацювало у мене.


Дякую, брат, жодна з відповідей не працювала з різних сайтів, окрім зниження версії socket.io :-( Це витратило багато часу. Щиро дякую. Нарешті, це працює з ^ 2.2.0
VenkateshMogili

4

Прочитавши багато підпроектів на StakOverflow та інших форумах, я знайшов робоче рішення для мене. Це рішення призначене для роботи без Express .

ось передумови.

  • зателефонуйте своєму скрипту js (src =) з того самого сервера, до якого буде підключено сокет (не CDN або локальний дзвінок)
  • переконайтеся, що однакова версія socket.io є на сервері та на клієнтській стороні
  • необхідні модулі вузла: fs , path , socket.io та для реєстрації
  • Встановіть Давайте зашифруємо certbot і сформуємо сертифікат для вашого домену або придбайте сертифікат SSL
  • jQuery оголошений перед socket.io.js на стороні клієнта
  • Кодування UTF-8

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

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

Це один з найяскравіших прикладів простого сервера NodeJS з інтеграцією socket.io; підтриманий
Нактус

3

Добре, у мене були деякі проблеми з тим, щоб це працювало, використовуючи самопідписаний сертифікат для тестування, тому я збираюся скопіювати свою установку, яка працювала для мене. Якщо ви не використовуєте самопідпис, ви, мабуть, не маєте цих проблем, сподіваємось!

Для початку, залежно від браузера 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

Ви, швидше за все, хочете встановити значення "true"

Наступна справа, якщо це сертифікат, що самопідписався, вам потрібно буде переглянути ваш сервер на окремій сторінці / вкладці та прийняти сертифікат або імпортувати його у свій браузер.

Щодо 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


3

Я стикаюся з проблемою під час створення програми чату за допомогою socket.io та node.js & React. Також ця проблема не є космічною для браузера Firefox, я стикаюся з такою ж проблемою і в Edge & Chrome.

"Запит перехресного походження заблоковано, і він використовується деякими іншими ресурсами ..."

Потім я завантажую корси в каталог проекту і поміщаю його у файл сервера index.js, як показано нижче: Для завантаження просто введіть команду за допомогою node.js:

npm встановити корси

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

Це дозволить CORS використовувати різні ресурси у файлах та дозволить запит на перехресне походження у браузері.


Та сама проблема виникає після впровадження. Працює в localhost, але не за межами
Пол Макберні

Так, я підтверджую. Не можу працювати на вулиці :(
Труонг Хоанг,

3

Якщо ви отримуєте io.set not a functionабо io.origins not a function, ви можете спробувати такі позначення:

import express from 'express';
import { Server } from 'socket.io';
const app = express();
const server = app.listen(3000);
const io = new Server(server, { cors: { origin: '*' } });

2

Це може бути проблемою із сертифікацією Firefox, і не обов’язково з вашим CORS. Запит CORS Firefox дає "Запит перехресного походження заблоковано", незважаючи на заголовки

Я стикався з тією самою проблемою, коли Socketio та Nodejs викидали помилку CORS у Firefox. У мене були сертифікати для * .myNodeSite.com, але я посилався на IP-адресу локальної мережі 192.168.1.10 для Nodejs. (IP-адреса WAN може також викликати ту саму помилку.) Оскільки сертифікат не відповідає посиланням на IP-адресу, Firefox видав цю помилку.


0

У мене була та сама проблема, і будь-яке рішення працювало для мене.

Причиною було те, що я використовую allowRequest, щоб прийняти або відхилити підключення, використовуючи маркер, який я передаю в параметрі запиту.

У мене є помилка в назві параметра запиту на стороні клієнта, тому підключення завжди відхилялося, але браузер скаржився на cors ...

Як тільки я виправив друкарську помилку, вона почала працювати, як очікувалося, і мені не потрібно нічого зайвого використовувати, достатньо глобальних налаштувань експрес-корсів.

Отже, якщо у вас щось працює, і ви використовуєте allowRequest, перевірте, чи працює ця функція належним чином, тому що помилки, які вона видає, відображаються як помилки cors у браузері. Якщо ви не додасте туди заголовки корсів вручну, коли ви хочете відхилити з'єднання, я думаю.


0

Використання однієї версії як для socket.io, так і для socket.io-клієнта виправило мою проблему.


0

Погляньте на це: Повний приклад

Сервер:

let exp = require('express');
let app = exp();

//UPDATE: this is seems to be deprecated
//let io = require('socket.io').listen(app.listen(9009));
//New Syntax:
const io = require('socket.io')(app.listen(9009));

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

Клієнт:

<!--LOAD THIS SCRIPT FROM SOMEWHERE-->
<script src="http://127.0.0.1:9009/socket.io/socket.io.js"></script>
<script>
    var socket = io("127.0.0.1:9009/", {
        "force new connection": true,
        "reconnectionAttempts": "Infinity", 
        "timeout": 10001, 
        "transports": ["websocket"]
        }
    );
</script>

Я пам’ятаю це з поєднання відповідей stackoverflow багато днів тому; але я не зміг знайти основні посилання, щоб згадати їх

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.