Socket.ioを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});
もちろん、サーバーとクライアントの.listen
関数と.connect
関数でそれぞれhttpsオプションを使用してhttpを切り替えると、逆の結果になります。 Socket.ioは、https経由ではなくhttp経由でアクセスできます。
どうすればこれを達成できますか?これは主にFacebookアプリに関するものであるため必要です。そのため、Facebookのルールに従ってhttpとhttpsの両方の接続オプションを提供する必要があります。
編集:それが問題について役立つ場合、私が受け取っているエラーは以下のとおりです
Failed to load resource: the server responded with a status of 404 (Not Found) http://DOMAIN/socket.io/socket.io.js
そしてこのため、私は次のような他のものを手に入れます:
Uncaught ReferenceError: io is not defined
問題は、サーバー側およびクライアントでに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;
});
サーバーの要点は次のとおりです。
そしてクライアント(翡翠の構文ですが、あなたは考えを理解します):
クライアントでは、io.connect()を呼び出す必要はありません。さらに、そこにあるあなたの選択肢についてはよくわかりません。タイプミス(、、)があるようですが、1.0のドキュメントでsecure:trueへの参照が見つかりません。
間違いなく、HTTPおよびHTTPSのnode.jsサーバーオブジェクトには、SSLの有無にかかわらず、任意の数のポートとインターフェイスでリッスンする機能を与える必要がありますが、これは現在実装されていないようです。 (server.listen(port 、[ホスト名]、[バックログ]、[コールバック])が、SSL /非SSLサーバーが混在している場合は機能しませんでした。)
stunnelすでに述べた回避策はもちろん実行可能なオプションですが、別のソフトウェアをインストールすることが望ましくない場合(node.js以外の依存関係を回避するため)、代わりにnode.jsで同じトンネリングをネイティブに実現できます(ポート80でHTTP、ポート443でHTTPSを想定)。
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);
これは、stunnelを使用するのと同じ効果があります。つまり、node.jsの「https」モジュールを冗長化しながら、2つの別々のsocket.ioサーバーインスタンスの必要性を回避します。
私は似たようなことをしましたが、2つの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インスタンスに対して、メッセージを2回挿入する必要があります。
良いオプションは、SSL処理を stunnel に委任し、コード内のSSLを忘れることです。
別のアプローチを使用して問題を解決し、暗号化されていないトランスポートのみをサポートするようにサーバーを構成し、httpsサポートに stunnel
を使用しました。
stunnel
のインストール方法については、これを確認できます post 。
次に、次の構成を使用しました。
#/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
サーバー(それに接続されているWebSocketサーバー)にアクセスすると、セキュリティエラーがスローされる可能性があります。エクスプレスでCORSを有効にする方法については、例を参照してください ここ 。
また、ヘッダーの*
をhttp://serverAddress , https://serverAddress
に変更する必要があります。すべてのサイトを許可することはお勧めできません。テストに使用してください。
http
サーバーとhttps
サーバーの間でAJAXを実行しようとしている場合も、同じことが言えます。念のため、エラーを投稿してください。