2013-06-24 36 views
11

Tôi đang cố gắng làm cho socket.io hoạt động cả trên các kết nối httphttps, nhưng có vẻ như với cấu hình của tôi, nó chỉ có thể hoạt động trên một trong số chúng.Sử dụng cả http và https cho socket.io

Với tùy chọn cấu hình bên dưới socket.io có thể truy cập ứng dụng của tôi qua https, nhưng khi cố gắng truy cập thông qua http thông thường, nó không thể kết nối và tôi nhận được lỗi.

var app = express() 
    , http= require('http').createServer(app) 
    , https = require('https').createServer(options, app) 
    , io = require('socket.io').listen(https, { log: false }) 

Và sau đó tôi có điều này

http.listen(80, serverAddress); 
https.listen(443, serverAddress); 

Về phía khách hàng tôi có điều này:

<script src='/socket.io/socket.io.js'></script> 

var socket = io.connect('https://<%= serverAddress %>', {secure: true, 'sync disconnect on unload' : true}); 

Tất nhiên nếu tôi chuyển đổi http với các tùy chọn https về chức năng .listen.connect của máy chủ và máy khách tương ứng tôi có kết quả ngược lại. Socket.io có thể truy cập thông qua http và không thông qua https.

Làm cách nào để đạt được điều này? Tôi cần nó chủ yếu là vì nó là về một ứng dụng facebook, vì vậy nó phải cung cấp cả hai tùy chọn kết nối http và https theo quy tắc facebook.

Chỉnh sửa: Trong trường hợp nó giúp về vấn đề này, các lỗi tôi đang nhận được là dưới

Failed to load resource: the server responded with a status of 404 (Not Found) http://DOMAIN/socket.io/socket.io.js 

Và vì điều này tôi nhận được những người khác như:

Uncaught ReferenceError: io is not defined 

Trả lời

2

Tôi đã làm điều gì đó tương tự và nó yêu cầu hai cá thể socket.io. Một cái gì đó như thế này:

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

Tất nhiên bạn sẽ cần phải tiêm tin nhắn hai lần: cho cả hai trường hợp socket.io.

Tùy chọn tốt là ủy quyền xử lý SSL cho stunnel và quên mã SSL trong mã của bạn.

+0

Một khách hàng từ 'http' có thể liên lạc với ai đó được kết nối với' https' không? Về 'stunnel' tôi đã thử nó và cũng' http-proxy', nhưng tôi không thể làm cho chúng hoạt động đúng. Bạn có thể cung cấp một ví dụ cho bất kỳ điều nào trong số này không? –

+0

Xin lỗi vì sự chậm trễ. Có, stunnel sẽ chăm sóc SSL và minh bạch giải mã các khách hàng của bạn kết nối với cổng https (443) để chúng xuất hiện như đang được kết nối với cổng http thể hiện (80). – MrTorture

+0

Dưới đây là một ý chính với cấu hình đơn giản hoạt động cho stunnel lắng nghe trên 443 và chuyển tiếp tất cả lưu lượng truy cập đến cổng 80 của cùng một máy chủ: https://gist.github.com/mbenedettini/5911415 – MrTorture

0

Tôi đoán Yêu cầu nguồn gốc chéo có thể là lý do khiến bạn gặp lỗi. Thay đổi trong giao thức được coi là thay đổi trong miền. Vì vậy, đối với trang được phục vụ thông qua http máy chủ truy cập https máy chủ (máy chủ websocket đính kèm với nó) có thể ném các lỗi bảo mật. Xem ví dụ here về cách bật CORS trong express.

Ngoài ra, bạn nên thay đổi * trong tiêu đề thành http://serverAddress , https://serverAddress. Cho phép tất cả các trang web không phải là ý tưởng hay, hãy sử dụng nó để thử nghiệm.

Điều tương tự cũng đúng nếu bạn đang cố gắng AJAX giữa các máy chủ httphttps của mình. Xin vui lòng gửi các lỗi, chỉ để chắc chắn về nó.

+0

Cảm ơn, tôi đã thêm lỗi i nhận được. Tôi đã thử cho phép CORS và sau đó tôi hiểu rằng cách tôi bao gồm socket.io tại 'đầu' của phía khách hàng nên thay đổi, do đó, theo yêu cầu luôn luôn là htpps và không liên quan đến url. Nó đã không làm việc khá mặc dù, tôi đã nhận một số lỗi khác như 'NETWORK_ERR: XMLHttpRequest ngoại lệ 101', nó phải là bởi vì tôi đang sử dụng Websockets và nếu không có sẵn, XHR bỏ phiếu. –

+0

Lỗi này xảy ra sau khi các lỗi bạn đã thêm được đề cập hoặc các lỗi bạn đã thêm đã được thay thế bằng lỗi này. – user568109

+0

Lỗi này thay thế ban đầu. –

4

Có thể cho rằng, đối tượng máy chủ node.js cho HTTP và HTTPS phải được cung cấp khả năng nghe trên số cổng và giao diện tùy ý, có và không có SSL, nhưng điều này dường như không được thực hiện. (Tôi đã có thể nhận được một máy chủ để lắng nghe trên hai cổng bằng cách truyền một máy chủ thứ hai không có trình xử lý yêu cầu làm đối số "xử lý" cho giao diện server.listen (handle, [callback]), ngoài server.listen (cổng , [hostname], [tồn đọng], [callback]), nhưng nó đã không làm việc với các máy chủ SSL/không SSL trộn.)

các stunnel workaround đã đề cập là tất nhiên là một lựa chọn khả thi, nhưng nếu không mong muốn cài đặt một phần mềm riêng biệt (để tránh phụ thuộc non-node.js), cùng một đường hầm có thể đạt được trong node.js (giả sử HTTP trên cổng 80 và HTTPS trên cổng 443):

var fs = require('fs'); 
var net = require('net'); 
var tls = require('tls'); 
var sslOptions = { 
    key: fs.readFileSync('server-key.pem'), 
    cert: fs.readFileSync('server-cert.pem') 
}; 
tls.createServer(sslOptions, function (cleartextStream) { 
    var cleartextRequest = net.connect({ 
     port: 80, 
     host: '127.0.0.1' 
    }, function() { 
     cleartextStream.pipe(cleartextRequest); 
     cleartextRequest.pipe(cleartextStream); 
    }); 
}).listen(443); 

Điều này sẽ có tác dụng tương tự như sử dụng stunnel. Nói cách khác, nó sẽ tránh được sự cần thiết của hai cá thể máy chủ socket.io riêng biệt, trong khi cũng làm cho mô-đun node.js "https" dư thừa.

13

Tôi tin rằng sự cố là cách bạn thiết lập socket.io ở phía máy chủ trên máy khách.

Đây là cách tôi làm cho nó hoạt động (chỉ dành cho bạn).

Server:

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); 
}); 

Chủ đầu tư:

script(src='/socket.io/socket.io.js') 
script. 
    var socket = io(); 
    socket.on('update', function(update){ 
    document.getElementById('update').innerHTML = update; 
    }); 

Dưới đây là những điểm mấu chốt cho máy chủ:

  1. đòi hỏi socket.io nhưng không gọi đó là phương pháp nghe (giả sử http và https a đã yêu cầu). Thay vào đó, chỉ cần giữ tham chiếu. (Var ioServer = require ('socket.io'))
  2. tạo của bạn http & https máy chủ
  3. tạo một đối tượng mới của ioServer
  4. ràng buộc máy chủ http và https (.listen)
  5. đính kèm http & Các phiên bản máy chủ https cho cá thể io. (.listen là bí danh cho .attach)
  6. thiết lập sự kiện io.

Và client (cú pháp ngọc nhưng bạn sẽ có được ý tưởng):

  1. bao gồm socket.io thẻ script
  2. gọi io và chụp tài liệu tham khảo
  3. thiết lập xử lý sự kiện của bạn

Trên máy khách, bạn không cần gọi io.connect(). Hơn nữa, tôi không chắc chắn về các lựa chọn của bạn ở đó. Dường như bạn có lỗi đánh máy (,,) và tôi không thể tìm thấy bất kỳ tham chiếu nào để bảo mật: đúng trong tài liệu 1.0.

Các vấn đề liên quan