node.js、带 SSL 的 socket.io
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6599470/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
node.js, socket.io with SSL
提问by Beyond
I'm trying to get socket.io running with my SSL certificate however, it will not connect.
我正在尝试使用我的 SSL 证书运行 socket.io,但是它无法连接。
I based my code off the chat example:
我的代码基于聊天示例:
var https = require('https');
var fs = require('fs');
/**
* Bootstrap app.
*/
var sys = require('sys')
require.paths.unshift(__dirname + '/../../lib/');
/**
* Module dependencies.
*/
var express = require('express')
, stylus = require('stylus')
, nib = require('nib')
, sio = require('socket.io');
/**
* App.
*/
var privateKey = fs.readFileSync('../key').toString();
var certificate = fs.readFileSync('../crt').toString();
var ca = fs.readFileSync('../intermediate.crt').toString();
var app = express.createServer({key:privateKey,cert:certificate,ca:ca });
/**
* App configuration.
*/
...
/**
* App routes.
*/
app.get('/', function (req, res) {
res.render('index', { layout: false });
});
/**
* App listen.
*/
app.listen(443, function () {
var addr = app.address();
console.log(' app listening on http://' + addr.address + ':' + addr.port);
});
/**
* Socket.IO server (single process only)
*/
var io = sio.listen(app,{key:privateKey,cert:certificate,ca:ca});
...
If I remove the SSL code it runs fine, however with it I get a request to http://domain.com/socket.io/1/?t=1309967919512
如果我删除 SSL 代码,它运行良好,但是有了它,我会收到一个对http://domain.com/socket.io/1/?t=1309967919512的请求
Note it's not trying https, which causes it to fail.
请注意,它没有尝试 https,这会导致它失败。
I'm testing on chrome, since it is the target browser for this application.
我正在测试 chrome,因为它是此应用程序的目标浏览器。
I apologize if this is a simple question, I'm a node/socket.io newbie.
如果这是一个简单的问题,我深表歉意,我是 node/socket.io 新手。
Thanks!
谢谢!
回答by kanaka
Use a secure URL for your initial connection, i.e. instead of "http://" use "https://". If the WebSocket transport is chosen, then Socket.IO should automatically use "wss://" (SSL) for the WebSocket connection too.
使用安全 URL 进行初始连接,即使用“https://”代替“http://”。如果选择了 WebSocket 传输,那么 Socket.IO 也应该自动为 WebSocket 连接使用“wss://”(SSL)。
Update:
更新:
You can also try creating the connection using the 'secure' option:
您还可以尝试使用“安全”选项创建连接:
var socket = io.connect('https://localhost', {secure: true});
回答by emonik
This is how I managed to set it up with express:
这就是我设法使用 express 进行设置的方式:
var fs = require( 'fs' );
var app = require('express')();
var https = require('https');
var server = https.createServer({
key: fs.readFileSync('./test_key.key'),
cert: fs.readFileSync('./test_cert.crt'),
ca: fs.readFileSync('./test_ca.crt'),
requestCert: false,
rejectUnauthorized: false
},app);
server.listen(8080);
var io = require('socket.io').listen(server);
io.sockets.on('connection',function (socket) {
...
});
app.get("/", function(request, response){
...
})
I hope that this will save someone's time.
我希望这会节省某人的时间。
Update :for those using lets encrypt use this
更新:对于那些使用让加密的人使用这个
var server = https.createServer({
key: fs.readFileSync('privkey.pem'),
cert: fs.readFileSync('fullchain.pem')
},app);
回答by Kuf
On the same note, if your server supports both httpand httpsyou can connect using:
同样,如果您的服务器支持两者http并且https您可以使用以下方法进行连接:
var socket = io.connect('//localhost');
to auto detect the browser schemeand connect using http/https accordingly. when in https, the transport will be secured by default, as connecting using
以自动检测浏览器方案,并使用HTTP / HTTPS连接相应。在 https 中时,默认情况下传输将受到保护,因为连接使用
var socket = io.connect('https://localhost');
will use secure web sockets - wss://(the {secure: true}is redundant).
将使用安全的网络套接字 - wss://(这 {secure: true}是多余的)。
for more information on how to serve both http and https easily using the same node server check out this answer.
有关如何使用同一节点服务器轻松提供 http 和 https 的更多信息,请查看此答案。
回答by clevertension
If your server certificated file is not trusted, (for example, you may generate the keystore by yourself with keytoolcommand in java), you should add the extra option rejectUnauthorized
如果您的服务器认证文件不受信任(例如,您可以使用java 中的keytool命令自己生成密钥库),您应该添加额外的选项 rejectUnauthorized
var socket = io.connect('https://localhost', {rejectUnauthorized: false});
回答by Jay Jariwala
check this.configuration..
检查这个.配置..
app = module.exports = express();
var httpsOptions = { key: fs.readFileSync('certificates/server.key'), cert: fs.readFileSync('certificates/final.crt') };
var secureServer = require('https').createServer(httpsOptions, app);
io = module.exports = require('socket.io').listen(secureServer,{pingTimeout: 7000, pingInterval: 10000});
io.set("transports", ["xhr-polling","websocket","polling", "htmlfile"]);
secureServer.listen(3000);
回答by slideshowp2
Server-side:
服务器端:
import http from 'http';
import https from 'https';
import SocketIO, { Socket } from 'socket.io';
import fs from 'fs';
import path from 'path';
import { logger } from '../../utils';
const port: number = 3001;
const server: https.Server = https.createServer(
{
cert: fs.readFileSync(path.resolve(__dirname, '../../../ssl/cert.pem')),
key: fs.readFileSync(path.resolve(__dirname, '../../../ssl/key.pem'))
},
(req: http.IncomingMessage, res: http.ServerResponse) => {
logger.info(`request.url: ${req.url}`);
let filePath = '.' + req.url;
if (filePath === './') {
filePath = path.resolve(__dirname, './index.html');
}
const extname = String(path.extname(filePath)).toLowerCase();
const mimeTypes = {
'.html': 'text/html',
'.js': 'text/javascript',
'.json': 'application/json'
};
const contentType = mimeTypes[extname] || 'application/octet-stream';
fs.readFile(filePath, (error: NodeJS.ErrnoException, content: Buffer) => {
if (error) {
res.writeHead(500);
return res.end(error.message);
}
res.writeHead(200, { 'Content-Type': contentType });
res.end(content, 'utf-8');
});
}
);
const io: SocketIO.Server = SocketIO(server);
io.on('connection', (socket: Socket) => {
socket.emit('news', { hello: 'world' });
socket.on('updateTemplate', data => {
logger.info(data);
socket.emit('updateTemplate', { random: data });
});
});
server.listen(port, () => {
logger.info(`Https server is listening on https://localhost:${port}`);
});
Client-side:
客户端:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Websocket Secure Connection</title>
</head>
<body>
<div>
<button id='btn'>Send Message</button>
<ul id='messages'></ul>
</div>
<script src='../../../node_modules/socket.io-client/dist/socket.io.js'></script>
<script>
window.onload = function onload() {
const socket = io('https://localhost:3001');
socket.on('news', function (data) {
console.log(data);
});
socket.on('updateTemplate', function onUpdateTemplate(data) {
console.log(data)
createMessage(JSON.stringify(data));
});
const $btn = document.getElementById('btn');
const $messages = document.getElementById('messages');
function sendMessage() {
socket.emit('updateTemplate', Math.random());
}
function createMessage(msg) {
const $li = document.createElement('li');
$li.textContent = msg;
$messages.appendChild($li);
}
$btn.addEventListener('click', sendMessage);
}
</script>
</body>
</html>
回答by Urasquirrel
For enterprise applications it should be noted that you should not be handling https in your code. It should be auto upgraded via IIS or nginx. The app shouldn't know about what protocols are used.
对于企业应用程序,应注意您不应在代码中处理 https。它应该通过 IIS 或 nginx 自动升级。该应用程序不应该知道使用了哪些协议。
回答by Gabriel Hautclocq
Depending on your needs, you could allow both secure and unsecure connections and still only use one Socket.io instance.
根据您的需要,您可以允许安全和不安全的连接,并且仍然只使用一个 Socket.io 实例。
You simply have to instanciate two servers, one for HTTP and one for HTTPS, then attach those servers to the Socket.io instance.
您只需实例化两台服务器,一台用于 HTTP,另一台用于 HTTPS,然后将这些服务器附加到 Socket.io 实例。
Server side :
服务器端 :
// needed to read certificates from disk
const fs = require( "fs" );
// Servers with and without SSL
const http = require( "http" )
const https = require( "https" );
const httpPort = 3333;
const httpsPort = 3334;
const httpServer = http.createServer();
const httpsServer = https.createServer({
"key" : fs.readFileSync( "yourcert.key" ),
"cert": fs.readFileSync( "yourcert.crt" ),
"ca" : fs.readFileSync( "yourca.crt" )
});
httpServer.listen( httpPort, function() {
console.log( `Listening HTTP on ${httpPort}` );
});
httpsServer.listen( httpsPort, function() {
console.log( `Listening HTTPS on ${httpsPort}` );
});
// Socket.io
const ioServer = require( "socket.io" );
const io = new ioServer();
io.attach( httpServer );
io.attach( httpsServer );
io.on( "connection", function( socket ) {
console.log( "user connected" );
// ... your code
});
Client side :
客户端 :
var url = "//example.com:" + ( window.location.protocol == "https:" ? "3334" : "3333" );
var socket = io( url, {
// set to false only if you use self-signed certificate !
"rejectUnauthorized": true
});
socket.on( "connect", function( e ) {
console.log( "connect", e );
});
If your NodeJS server is different from your Web server, you will maybe need to set some CORS headers. So in the server side, replace:
如果您的 NodeJS 服务器与您的 Web 服务器不同,您可能需要设置一些 CORS 标头。所以在服务器端,替换:
httpServer.listen( httpPort, function() {
console.log( `Listening HTTP on ${httpPort}` );
});
httpsServer.listen( httpsPort, function() {
console.log( `Listening HTTPS on ${httpsPort}` );
});
With:
和:
const httpServer = http.createServer( (req, res) => {
res.setHeader( "Access-Control-Allow-Origin" , "*" );
res.setHeader( "Access-Control-Request-Method", "*" );
res.setHeader( "Access-Control-Allow-Methods" , "*" );
res.setHeader( "Access-Control-Allow-Headers" , "*" );
if ( req.method === "OPTIONS" ) {
res.writeHead(200);
res.end();
return;
}
});
const httpsServer = https.createServer({
"key" : fs.readFileSync( "yourcert.key" ),
"cert": fs.readFileSync( "yourcert.crt" )
}, (req, res) => {
res.setHeader( "Access-Control-Allow-Origin" , "*" );
res.setHeader( "Access-Control-Request-Method", "*" );
res.setHeader( "Access-Control-Allow-Methods" , "*" );
res.setHeader( "Access-Control-Allow-Headers" , "*" );
if ( req.method === "OPTIONS" ) {
res.writeHead(200);
res.end();
return;
}
});
And of course adjust the values of the headers according to your needs.
当然,根据您的需要调整标题的值。
回答by Kathy
This is my nginx config file and iosocket code. Server(express) is listening on port 9191. It works well: nginx config file:
这是我的 nginx 配置文件和 iosocket 代码。Server(express) 正在监听 9191 端口。它运行良好:nginx 配置文件:
server {
listen 443 ssl;
server_name localhost;
root /usr/share/nginx/html/rdist;
location /user/ {
proxy_pass http://localhost:9191;
}
location /api/ {
proxy_pass http://localhost:9191;
}
location /auth/ {
proxy_pass http://localhost:9191;
}
location / {
index index.html index.htm;
if (!-e $request_filename){
rewrite ^(.*)$ /index.html break;
}
}
location /socket.io/ {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://localhost:9191/socket.io/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
ssl_certificate /etc/nginx/conf.d/sslcert/xxx.pem;
ssl_certificate_key /etc/nginx/conf.d/sslcert/xxx.key;
}
Server:
服务器:
const server = require('http').Server(app)
const io = require('socket.io')(server)
io.on('connection', (socket) => {
handleUserConnect(socket)
socket.on("disconnect", () => {
handleUserDisConnect(socket)
});
})
server.listen(9191, function () {
console.log('Server listening on port 9191')
})
Client(react):
客户端(反应):
const socket = io.connect('', { secure: true, query: `userId=${this.props.user._id}` })
socket.on('notifications', data => {
console.log('Get messages from back end:', data)
this.props.mergeNotifications(data)
})

