Socket.io + Node.js跨域请求被阻止


77

我正在使用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 2014年

Answers:


92

简单的服务器端修复

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

要么

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

要么

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

* 独自一人行不通,这使我失望。


5
我使用的是最新版本,它不是,它给我连接被拒绝的错误
游戏玩家

@gamer可能会遵循所有最初的原则,然后上升,例如,我的防火墙是否阻塞了端口?我可以ping我的服务器等吗?
Jason Sebring

你是个天才。这是快递的最佳解决方案!
abelabbesnabi

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-adapter-mongodb 0.0.2的socket.io-client 2.2.0
The Bumpaster

1
我很感激我找到了这篇文章,今天我花了5到6个小时尝试在套接字服务器上启用CORS。我确实尝试了在stackoverflow上可以找到的每个方法。这是唯一对我有用的方法。我不明白为什么io.origin(“:”)在这种情况下也不起作用。我过去曾构建过其他套接字服务器,但从未遇到过问题。如果有人有理论,我很想听听。无论如何,非常感谢分享!
octavemirbeau

33

您可以尝试origins在服务器端设置选项以允许跨域请求:

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

这里 http://yourdomain.com:80是您要允许请求的来源。

您可以在此处阅读有关origins格式的更多信息


12

对于任何在这里寻找新Socket.io(3.x)的人来说,迁移文档都非常有用。

特别是以下代码段:

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

9

我在上面尝试过,对我没有任何帮助。以下代码来自socket.io文档,并且可以正常工作。

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

4

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

这是带有socket.io集成的裸机NodeJS服务器的最清楚的例子之一。投票
Nactus

4

使用socket.io和node.js&React制作聊天应用程序时遇到问题。同样,这个问题对Firefox浏览器来说不是空间问题,我在Edge&Chrome中也面临同样的问题。

“跨域请求已被阻止,其他一些资源正在使用它……”

然后我将cors下载到项目目录中,并将其放入服务器文件index.js中,如下所示:要下载,只需使用node.js键入命令:

NPM安装CORS

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

这将允许CORS被文件中的不同资源使用,并允许浏览器中的跨源请求。


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

如果您获得io.set not a functionio.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有任何问题。Firefox CORS请求提供“跨域请求已阻止”,尽管标题

我遇到了与Socketio和Nodejs相同的确切问题,在Firefox中抛出了CORS错误。我有* .myNodeSite.com的证书,但是我为Nodejs引用了LAN IP地址192.168.1.10。(WAN IP地址也可能引发相同的错误。)由于Cert与IP地址引用不匹配,因此Firefox抛出了该错误。


0

我遇到了同样的问题,任何解决方案都对我有用。

原因是我正在使用allowRequest通过我在查询参数中传递的令牌接受或拒绝连接。

我在客户端的查询参数名称中有错字,因此连接始终被拒绝,但是浏览器抱怨错误...

修正拼写错误后,它就会按预期方式开始工作,并且我不需要使用任何其他功能,全局express cors设置就足够了。

因此,如果有什么对您有用,并且您正在使用allowRequest,请检查此函数是否正常运行,因为它引发的错误在浏览器中显示为cors错误。我想除非您想拒绝连接时手动在此处添加cors标头。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.