Node.js, socket.io с SSL
Я пытаюсь запустить socket.io с моим SSL-сертификатом, но он не будет подключаться.
Я основывал свой код на примере чата:
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});
...
Если я удалю код SSL, он работает нормально, но с ним я получаю запрос http://domain.com/socket.io/1/?t=1309967919512
Обратите внимание, что это не попытка https, из-за чего он терпит неудачу.
Я тестирую хром, так как он является целевым браузером для этого приложения.
Извиняюсь, если это простой вопрос, я новичок node/socket.io.
Спасибо!
Ответы
Ответ 1
Используйте безопасный URL для вашего первоначального соединения, то есть вместо "http://" используйте "https://". Если выбран транспорт WebSocket, то Socket.IO должен автоматически использовать "wss://" (SSL) для соединения WebSocket.
Обновление
Вы также можете попробовать создать соединение с помощью опции "secure":
var socket = io.connect('https://localhost', {secure: true});
Ответ 2
Вот как мне удалось настроить его с помощью выражения:
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){
...
})
Я надеюсь, что это сэкономит время.
Обновление: для тех, кто использует, позволяет шифровать этот
var server = https.createServer({
key: fs.readFileSync('privkey.pem'),
cert: fs.readFileSync('fullchain.pem')
},app);
Ответ 3
В том же случае, если ваш сервер поддерживает как http
, так и https
, вы можете подключиться, используя:
var socket = io.connect('//localhost');
to автоматически определить схему браузера и соответственно подключиться с помощью http/https. когда в https, транспорт будет защищен по умолчанию, поскольку соединение с использованием
var socket = io.connect('https://localhost');
будет использовать защищенные веб-сокеты - wss://
({secure: true}
является избыточным).
для получения дополнительной информации о том, как легко обслуживать как http, так и https, используя тот же сервер node, этот ответ.
Ответ 4
Если вашему сертифицированному файлу сервера не доверяют (например, вы можете создать хранилище ключей самостоятельно с помощью команды keytool в java), вы должны добавить дополнительную опцию rejectUnauthorized
var socket = io.connect('https://localhost', {rejectUnauthorized: false});
Ответ 5
проверить 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);
Ответ 6
Серверный:
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}');
});
Сторона клиента:
<!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>
Ответ 7
Это мой конфигурационный файл nginx и код iosocket. Сервер (экспресс) прослушивает порт 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;
}
Сервер:
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')
})
Клиент (реагируют):
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)
})
Ответ 8
Для корпоративных приложений следует отметить, что вы не должны обрабатывать https в своем коде. Это должно быть автоматически обновлено через IIS или nginx. Приложение не должно знать о том, какие протоколы используются.
Ответ 9
В зависимости от ваших потребностей, вы можете разрешить как безопасные, так и незащищенные соединения, и при этом использовать только один экземпляр Socket.io.
Вам просто нужно создать два сервера, один для HTTP и один для HTTPS, а затем подключить эти серверы к экземпляру Socket.io.
Сторона сервера:
// 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
});
Клиентская сторона:
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 );
});
Если ваш сервер NodeJS отличается от вашего веб-сервера, вам, возможно, потребуется установить некоторые заголовки CORS. Поэтому на стороне сервера замените:
httpServer.listen( httpPort, function() {
console.log( 'Listening HTTP on ${httpPort}' );
});
httpsServer.listen( httpsPort, function() {
console.log( 'Listening HTTPS on ${httpsPort}' );
});
С:
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;
}
});
И, конечно, настройте значения заголовков в соответствии с вашими потребностями.