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

时间:2014-06-05 10:47:10

标签: node.js sockets socket.io cors

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

我也在app根目录中使用.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"

21 个答案:

答案 0 :(得分:56)

简单服务器端修复

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

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

io.origins('*:*') // for latest version
仅仅{p> *并没有让我陷入兔子洞的工作。

答案 1 :(得分:26)

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

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

此处http://yourdomain.com:80是您要允许来自的来源。

您可以详细了解origins格式here

答案 2 :(得分:18)

对于在这里寻找新Socket.io(3.x)的人来说,migration documents很有帮助。

特别是以下代码段:

@code
{
    RenderFragment<RenderFragment> userContent 
        => context => @<text>Some stuff @context more stuff</text>;
}

答案 3 :(得分:6)

我在上面尝试过,对我没有任何帮助。以下代码来自socket.io documentation,并且有效。

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

答案 4 :(得分:3)

这可能是Firefox的认证问题,不一定是您的CORS有任何问题。 Firefox CORS request giving 'Cross-Origin Request Blocked' despite headers

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

答案 5 :(得分:3)

我只是想说,在尝试了一堆东西之后,解决了我的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,您可能会发现尝试使用socket.io时CORS问题消失了。至少对我有用。

答案 6 :(得分: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: '*' } });

答案 7 :(得分:3)

我正在使用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);

答案 8 :(得分:2)

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

答案 9 :(得分:1)

使用socket.io和node.js&React制作聊天应用程序时遇到问题。同样,此问题对于Firefox浏览器而言不是唯一的问题,我在Edge&Chrome中也面临同样的问题。

  

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

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

  

npm install cors

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

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

答案 10 :(得分:1)

好的,在使用自签名证书进行测试时,我遇到了一些问题,因此我将复制适用于我的设置。如果您不使用自签名证书,则可能不会出现这些问题!

要开始使用取决于您的浏览器的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

答案 11 :(得分:1)

如果没有任何效果 在运行窗口中运行 window + r

chrome.exe --user-data-dir =“ C:/ Chrome开发者会话” --disable-web-security

使用此方法解决了我的问题,安装cors插件适用于php,node rest apis,但是在我启用cors套接字停止工作时使用socket.io的情况。 我在不同的端口上同时运行

localhost:3001,而ng在localhost:4200上

更新-我现在正在使用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}`);
});

答案 12 :(得分:0)

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

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

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

一旦我修正了错字,它就会按预期的方式开始工作,而且我不需要使用任何多余的东西,全局express cors设置就足够了。

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

答案 13 :(得分:0)

socket.io和socket.io-client使用相同版本修复了我的问题。

答案 14 :(得分:0)

看看这个: Complete Example

服务器:

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答案中得出的结论;但我找不到提及他们的主要链接

答案 15 :(得分:0)

有时在节点服务器停止时会遇到此问题。 因此,请检查您的节点服务器是否正常工作。

然后你可以使用 io.set('origins', 'http://yourdomain.com:PORT_NUMBER');

答案 16 :(得分:0)

我在 easyRTC 中使用了 socket.io 2.4.0 版本,并在 server_ssl.js 中使用了以下代码,这对我有用

io = require("socket.io")(webServer, {
  handlePreflightRequest: (req, res) => {
    res.writeHead(200, {
      "Access-Control-Allow-Origin": req.headers.origin,
      "Access-Control-Allow-Methods": "GET,POST,OPTIONS",
      "Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept, Referer, User-Agent, Host, Authorization",
      "Access-Control-Allow-Credentials": true,
      "Access-Control-Max-Age":86400
    });
    res.end();
  }
});

答案 17 :(得分:0)

如果您在 Chrome、Safari 和其他浏览器上运行 socket.io 应用程序,但在 Firefox 中仍然遇到 CORS 问题,并且您使用的是自签名证书,那么问题在于 Firefox 不接受自签名证书默认情况下,您必须通过转到 Firefox 的首选项 > 证书 > 查看证书 > 添加例外来添加例外。

如果您不这样做,Firefox 会显示您发布的具有误导性的错误,但在其开发人员工具的深处,您会发现此错误:MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT。这表明 Firefox 根本不接受该证书,因为它是自签名的。

答案 18 :(得分:0)

以下是官方文档中的解决方案:

<块引用>

Since Socket.IO v3, you need to explicitly enable Cross-Origin Resource Sharing (CORS).

const io = require("socket.io")(httpServer, {cors: {
origin: "https://example.com", // or "*"
methods: ["GET", "POST"]}});

答案 19 :(得分:0)

const options = {
  cors: {
    origin:
      String(process.env.ORIGINS_STRING) === "ALL"
        ? true
        : String(process.env.ORIGINS_STRING).split(","),
    methods: ["GET", "PUT", "POST", "DELETE"],
    allowedHeaders: [
      "Access-Control-Allow-Headers",
      "X-Requested-With",
      "X-Access-Token",
      "Content-Type",
      "Host",
      "Accept",
      "Connection",
      "Cache-Control",
    ],
    credentials: true,
    optionsSuccessStatus: 200,
  },
};

在 .env 文件中:

ORIGINS_STRING=ALL

ORIGINS_STRING=http://localhost:8080,http://localhost:8081

答案 20 :(得分:0)

我只是将 socket.io 的版本从 2.x.x 更新到后端的 4.1.2 并做了同样的事情,即。将前端的 socket.io-client 版本从 2.x.x 更新到 4.1.2 ....它工作了