RailsやFlaskで実装したWebアプリケーションで、socket.ioを使ったチャット機能を追加する場合、
それらのアプリケーションで配信したHTMLに、socket.ioのスクリプトをロードして使う必要がありますが、
socket.ioが起動しているポートをHTMLに記述しなければなりません。
Production環境では、余計なポートを開放したくないので、クライアントからsocket.ioに接続する場合、
Webアプリケーションと同じポートで接続できるようにしたいところです。
前面にNginxをたてて、socket.ioのプロキシとして動作させれば実現できそうです。
前提
- Webアプリケーションは、ポート80でアクセス可能
- socket.ioは、ポート3000で起動
- Nginxは出来るだけ最新のバージョンを使用(v1.6とか)
手順
- Webアプリケーションも、socket.ioもNginx経由で、クライアント(Webブラウザ)から接続できるようにする。
- path:
/socket.io/
にアクセスがあったら、起動しているsocket.ioのURLに転送する。(Proxy)
Nginxの設定
/socket.io/
にアクセスがあったら、socket.ioに転送するだけです。
// app.conf
upstream io_nodes {
ip_hash;
// 起動しているsocket.ioの接続先URL
server 127.0.0.1:3000;
}
server {
listen 80;
server_name foo.docker.dev;
// Webアプリケーション側
location / {
uwsgi_pass unix:///tmp/uwsgi.sock;
include uwsgi_params;
client_max_body_size 20M;
}
// Webブラウザからsocket.ioにアクセスする際のパス`/socket.io/`だった場合、socket.ioに転送(Proxy)
location /socket.io/ {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_pass http://io_nodes;
}
}
HTML
Nginxの設定ができていれば、<script>
タグで、socket.ioのスクリプトを読み込むのも、初期化するのもホスト名、ポート番号などを書かなくて良くなります。
また、Iptablesなどで、socket.io用のポートは開放する必要はなくなります。
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
socket.on('connect', function(msg) {
console.log(msg);
});
socket.on('chat message', function(msg) {
alert(msg);
});
socket.on('test message', function(msg) {
console.log(msg);
});
</script>
追記
ただ、開発環境でnginxを立ててとかやるのは、めんどくさいので、直接socket.ioにも接続できるようにしたい場合は、
Webアプリケーション側で開発時にだけ、socket.ioの接続先URLを変数か何かに格納しておけばよいでしょう。
<script id="socketIO" src="{{ IO_DIRECT_URL or '' }}/socket.io/socket.io.js"></script>
<script>
var url;
{%- if IO_DIRECT_URL -%}
url = {{ IO_DIRECT_URL|tojson|safe }};
{%- endif -%}
var socket = io(url ? url : undefined);
socket.on('connect', function(msg) {
console.log(arguments);
console.log(msg);
});
socket.on('chat message', function(msg) {
alert(msg);
});
socket.on('test message', function(msg) {
console.log(msg);
});
</script>