Node.js 对socket.io同时使用http和https
我试图使socket.io在Node.js 对socket.io同时使用http和https,node.js,ssl,express,socket.io,Node.js,Ssl,Express,Socket.io,我试图使socket.io在http和https连接上都能工作,但在我的配置中,它似乎只能在其中一个连接上工作 使用下面的配置选项,socket.io可以通过https访问我的应用程序,但当尝试通过常规http访问时,它无法连接,并且我收到错误 var app = express() , http= require('http').createServer(app) , https = require('https').createServer(options, app) ,
http
和https
连接上都能工作,但在我的配置中,它似乎只能在其中一个连接上工作
使用下面的配置选项,socket.io可以通过https访问我的应用程序,但当尝试通过常规http访问时,它无法连接,并且我收到错误
var app = express()
, http= require('http').createServer(app)
, https = require('https').createServer(options, app)
, io = require('socket.io').listen(https, { log: false })
后来我有了这个
http.listen(80, serverAddress);
https.listen(443, serverAddress);
在客户端,我有以下内容:
<script src='/socket.io/socket.io.js'></script>
var socket = io.connect('https://<%= serverAddress %>', {secure: true, 'sync disconnect on unload' : true});
正因为如此,我还得到了其他一些,如:
Uncaught ReferenceError: io is not defined
我做过类似的事情,它需要两个socket.io实例。大概是这样的:
var express = require('express');
var oneServer = express.createServer();
var anotherServer = express.createServer();
var io = require('socket.io');
var oneIo = io.listen(oneServer);
var anotherIo = io.listen(anotherServer);
当然,您需要注入两次消息:对于两个socket.io实例
一个好的选择是将SSL处理委托给您的代码,并在代码中忘记SSL。我猜跨源请求可能是您出错的原因。协议中的更改被视为域中的更改。因此,对于通过
http
服务器提供的页面,访问https
服务器(连接到它的websocket服务器)可能会引发安全错误。请参见有关如何在express中启用CORS的示例
您还应该将标题中的*
更改为http://serverAddress , https://serverAddress
。允许所有站点不是一个好主意,使用它进行测试
如果您试图在
http
和https
服务器之间使用AJAX,情况也是如此。请发布错误,只是为了确定它。我使用不同的方法解决了问题,我将服务器配置为仅支持未加密传输,并用于https支持
有关如何安装stunnel
的信息,请检查此项
然后,使用以下con配置:
#/etc/stunnel/stunnel.conf
cert = /var/www/node/ssl/encryption.pem
[node]
accept = 443
connect = 80
最后,我使用以下方法连接客户端:
var socket = that.socket = io.connect('//'+server);
这将相应地使用http/https进行连接。可以说,http和https的node.js服务器对象应该能够侦听任意数量的端口和接口,无论是否使用SSL,但目前似乎尚未实现。(我能够让一台服务器在两个端口上侦听,方法是将没有请求侦听器的第二台服务器作为“句柄”参数传递给server.listen(句柄,[callback])接口,以及server.listen(端口,[hostname],[backlog],[callback]),但它不能与SSL/非SSL服务器混合使用。) 前面提到的stunnel解决方案当然是一个可行的选择,但如果不希望安装单独的软件(以避免非node.js依赖关系),则可以在node.js中以本机方式实现相同的隧道(假设端口80上有HTTP,端口443上有HTTPS):
这将具有与使用特技相同的效果。换句话说,它将避免需要两个单独的socket.io服务器实例,同时也使node.js“https”模块冗余。我认为问题在于您在服务器端和客户端设置socket.io的方式 以下是我如何让它工作的(只为你) 服务器:
var debug = require('debug')('httpssetuid');
var app = require('../app');
var http = require('http');
var https = require('https');
var fs = require('fs');
var exec = require('child_process').exec;
var EventEmitter = require('events').EventEmitter;
var ioServer = require('socket.io');
var startupItems = [];
startupItems.httpServerReady = false;
startupItems.httpsServerReady = false;
var ee = new EventEmitter();
ee.on('ready', function(arg) {
startupItems[arg] = true;
if (startupItems.httpServerReady && startupItems.httpsServerReady) {
var id = exec('id -u ' + process.env.SUDO_UID, function(error, stdout, stderr) {
if(error || stderr) throw new Error(error || stderr);
var uid = parseInt(stdout);
process.setuid(uid);
console.log('de-escalated privileges. now running as %d', uid);
setInterval(function cb(){
var rnd = Math.random();
console.log('emitting update: %d', rnd);
io.emit('update', rnd);
}, 5000);
});
};
});
app.set('http_port', process.env.PORT || 80);
app.set('https_port', process.env.HTTPS_PORT || 443);
var httpServer = http.createServer(app);
var opts = {
pfx: fs.readFileSync('httpssetuid.pfx')
};
var httpsServer = https.createServer(opts, app);
var io = new ioServer();
httpServer.listen(app.get('http_port'), function(){
console.log('httpServer listening on port %d', app.get('http_port'));
ee.emit('ready', 'httpServerReady');
});
httpsServer.listen(app.get('https_port'), function(){
console.log('httpsServer listening on port %d', app.get('https_port'));
ee.emit('ready', 'httpsServerReady');
});
io.attach(httpServer);
io.attach(httpsServer);
io.on('connection', function(socket){
console.log('socket connected: %s', socket.id);
});
script(src='/socket.io/socket.io.js')
script.
var socket = io();
socket.on('update', function(update){
document.getElementById('update').innerHTML = update;
});
客户端:
var debug = require('debug')('httpssetuid');
var app = require('../app');
var http = require('http');
var https = require('https');
var fs = require('fs');
var exec = require('child_process').exec;
var EventEmitter = require('events').EventEmitter;
var ioServer = require('socket.io');
var startupItems = [];
startupItems.httpServerReady = false;
startupItems.httpsServerReady = false;
var ee = new EventEmitter();
ee.on('ready', function(arg) {
startupItems[arg] = true;
if (startupItems.httpServerReady && startupItems.httpsServerReady) {
var id = exec('id -u ' + process.env.SUDO_UID, function(error, stdout, stderr) {
if(error || stderr) throw new Error(error || stderr);
var uid = parseInt(stdout);
process.setuid(uid);
console.log('de-escalated privileges. now running as %d', uid);
setInterval(function cb(){
var rnd = Math.random();
console.log('emitting update: %d', rnd);
io.emit('update', rnd);
}, 5000);
});
};
});
app.set('http_port', process.env.PORT || 80);
app.set('https_port', process.env.HTTPS_PORT || 443);
var httpServer = http.createServer(app);
var opts = {
pfx: fs.readFileSync('httpssetuid.pfx')
};
var httpsServer = https.createServer(opts, app);
var io = new ioServer();
httpServer.listen(app.get('http_port'), function(){
console.log('httpServer listening on port %d', app.get('http_port'));
ee.emit('ready', 'httpServerReady');
});
httpsServer.listen(app.get('https_port'), function(){
console.log('httpsServer listening on port %d', app.get('https_port'));
ee.emit('ready', 'httpsServerReady');
});
io.attach(httpServer);
io.attach(httpsServer);
io.on('connection', function(socket){
console.log('socket connected: %s', socket.id);
});
script(src='/socket.io/socket.io.js')
script.
var socket = io();
socket.on('update', function(update){
document.getElementById('update').innerHTML = update;
});
以下是服务器的关键点:
在客户端上,不需要调用io.connect()。此外,我不确定你在那里的选择。看起来您有一个输入错误(,),我在1.0文档中找不到任何关于安全的参考:true。来自
http
的客户端是否能够与连接到https
的人通信?关于stunnel
我已经试过了,也试过了httpproxy
,但是我不能让它们正常工作。你能举个例子吗?抱歉耽搁了。是的,stunnel负责SSL并透明地解密连接到https端口(443)的客户端,使它们看起来像是连接到express http端口(80)。以下是stunnel的一个简单配置要点,该配置监听443并将所有传入流量转发到同一主机的端口80:谢谢,我添加了收到的错误。我尝试启用CORS,然后我了解到,我在客户端头部
包含socket.io的方式应该改变,因为请求始终是针对htpps的,而不是相对于url的。但是它没有很好地工作,我遇到了一些其他错误,比如NETWORK\u ERR:XMLHttpRequest Exception 101
,这一定是因为我使用的是WebSocket,如果不可用,则是XHR轮询。这个错误是在您添加的问题错误之后出现的吗,或者您添加的错误已被此错误替换。现在发生的错误是由于同源策略造成的。你能说出引起这个错误的线路吗。可能CORS请求失败是因为某些url。我使用了此方法,但它在我的系统中不起作用,对于http,所有东西都能正常工作,但我不知道如何配置https,我使用了节点、套接字io、redis和rails,所以我始终需要连接端口9876http.listen(9876,function(){console.log('listening on*:9876');})代码>,我在stunnel.conf中添加了您的代码。但不起作用。你能帮助我吗?