为Socket.IO设置CORs标头

时间:2017-11-30 15:00:38

标签: angularjs node.js socket.io cors apache2

我试图通过Apache代理使用socket.io服务但是我一直收到这个错误:

  

当请求的凭据模式为“include”时,响应中的“Access-Control-Allow-Origin”标头的值不能是通配符“*”。因此,不允许原点“http://localhost:18996”访问。 XMLHttpRequest发起的请求的凭证模式由withCredentials属性控制。

这是我的apache配置

<VirtualHost *:443>
    ServerName myserver.com

    Header always set Access-Control-Allow-Origin "*"
    Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
    Header always set Access-Control-Max-Age "1000"
    Header always set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, cl$

    RewriteEngine On
    RewriteCond %{REQUEST_METHOD} OPTIONS
    RewriteRule ^(.*)$ $1 [R=200,L]

    DocumentRoot /var/www/api
    SSLEngine on
    SSLCertificateFile /etc/ssl/MYSSL
    SSLCertificateKeyFile /etc/ssl/MYSSL
    ProxyRequests Off
    ProxyPreserveHost On
    ProxyVia Full
    <Proxy *>
        Require all granted
    </Proxy>
    <Location /api1>
        ProxyPass http://127.0.0.1:8005
        ProxyPassReverse http://127.0.0.1:8005
    </Location>
    <Location /api2>
        ProxyPass http://127.0.0.1:9000
        ProxyPassReverse http://127.0.0.1:9000
    </Location>
    <Location /socketioservice>
        ProxyPass http://127.0.0.1:9090
        ProxyPassReverse http://127.0.0.1:9090
    </Location>
</VirtualHost>

这是我的Node JS代码:

const express    = require('express'),
      app        = express(),
      bodyParser = require('body-parser'),
      server     = require('http').createServer(app),
      io         = require('socket.io')(server);

app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});

io.on('connection', user => {
    //Socket.io Functions
});

server.listen(8000, () => console.log('Server Running'));

我有其他NodeJS服务在你看到的同一个盒子上运行,那些只是Express JS Apis,它们工作正常(使用你在socket.io代码中看到的相同的cors配置)。

我试图像这样改变角色设置:

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json()); 
app.use(cors({ origin: '*' }));

app.use(function (req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
    res.header('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
    res.setHeader('Access-Control-Allow-Credentials', false);
    next();
});

const server = app.listen(cross.NormalizePort(process.env.PORT || 9090));
const io = require('socket.io').listen(server, {
    log: false,
    agent: false,
    origins: '*:*',
    transports: ['websocket', 'htmlfile', 'xhr-polling', 'jsonp-polling', 'polling']
});

但这给了我完全相同的结果。我试图在没有cors的情况下完全使用它,我也得到同样的错误。

我在AngularJS应用程序中使用它,工厂如此:

.factory('Links', ['$rootScope', function ($rootScope) {
    let socket = io.connect('https://myurl/socketioservice', { secure: true });
    return {
        on: function (eventName, callback) {
            socket.on(eventName, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    callback.apply(socket, args);
                });
            });
        },
        emit: function (eventName, data, callback) {
            socket.emit(eventName, data, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    if (callback) {
                        callback.apply(socket, args);
                    }
                });
            });
        }
    };
}])

我已经验证了socket.io服务通过在本地运行它可以正常工作我可以使用http://localhost:8000连接到它。当我将它部署到生产框时,我可以像这样使用它:http://prodipaddress:8000并且也可以使用它。

但是,我需要能够运行Apache代理,否则由于防火墙规则,无法从网络外部访问它。

如何配置cors以允许我连接到我的socket.io服务?

1 个答案:

答案 0 :(得分:1)

您正在使用凭据模式(意味着您要从角应用程序发送一些身份验证cookie),而对于CORS规范,您无法在此模式下使用通配符*。

您应该更改Access-Control-Allow-Origin标头以匹配生成请求的特定主机

你可以改变这一行:

res.header('Access-Control-Allow-Origin', '*');

res.header('Access-Control-Allow-Origin', 'http://localhost:18996');

但要更通用:

res.setHeader('Access-Control-Allow-Origin', req.header('origin') 
|| req.header('x-forwarded-host') || req.header('referer') || req.header('host'));