https://で接続するときにはwss://
現在ChromeでセキュアHTTP(https://)接続をしようとすると,WebSocketも強制的にSecure WebSocketになるので,その対応.
Tornado側の対応
セキュア接続に必要な証明書と鍵(.crtファイルと.keyファイル)はサーバ毎に用意されている(取得しておく)もので,そのコピーを持って来て読み込める場所に設置しておき,Tornadoのサーバ生成を定義する段階,つまりtornado.web.Application()
関数を実行してapplicationインスタンスを作り,それを回し始める時にssl_option
で読み込ませる.
ただし,外からhttpで見えるフォルダ,例えばクライアントhtml,jsファイルと同じフォルダに置いておくと,セキュリティ上問題があるので,外からは見えない(例えばpublic_htmlの上の階層など)フォルダに置いて置いて,そこから読み込む必要がある.
サーバ側のコードが今までの非セキュアなWebSocketとはちょっと違うことに注意.
インスタンスを生成するために証明書と鍵(certファイルとkeyファイル)を読み込む必要があり,前項のようなtornado.web.Application()
関数に全部突っ込んでインスタンスを生成するための書法が2017年11月現在まだ完成していないため,暫定的にこうなっていると思われる.
そのため事前にapplicationインスタンスを作っておく必要がある.
(WebSocketサービスだけなら今までのようにtonado.web.Application
クラスのインスタンスで回せていたが,Secureになると,applicationを生成しておいてから,それをtornado.httpserver.HTTPServer
クラスのインスタンスを使って回す形になる)
コード例
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
import tornado.websocket
import tornado.template
import tornado.httpserver
server_client_list = []
class SecureWSServer(tornado.websocket.WebSocketHandler):
def check_origin(self, origin):
return True
def open(self):
server_client_list.append(self)
print("New Client Connected.")
def on_message(self, message):
print("Received message:" + message)
for a_server_client in server_client_list:
a_server_client.write_message(message)
def on_close(self):
if self in server_client_list:
server_client_list.remove(self)
print("Client Connection Closed")
application = tornado.web.Application(\
[(r'/ws_secure_connect', SecureWSServer)])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(\
application, ssl_options={
"certfile": "mycert.crt",\
"keyfile": "mykey.key"})
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html>
<!-- WSSecureConnect_Client.html -->
<html lang="ja">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8" />
<title>Secure WebSocket</title>
<script type="text/javascript" src="WSSecureConnect_Client.js">
</script>
</head>
<body>
<div id="controll_field">
<p>
<input type="button" value="接続開始" onclick="startConnection()" />
<input type="button" value="接続終了" onclick="exitConnection()" />
</p>
<form>
<input type="text" name="text_field" value="ここに入力して「送信」ボタンを押してください." />
<input type="button" name="send_button" value="送信" onclick="sendMessage(this.form.elements['text_field'].value)" />
</form>
</div>
<div id="view_field">
<p>初期テキスト</p>
</div>
</body>
</html>
// WSSecureConnect_Client.js
'use strict';
window.addEventListener('load', function(){
window.webSocket = null;
window.wsServerUrl = 'wss://localhost:8888/ws_secure_connect'; // SecureWS
}, false);
window.addEventListener('unload', function(event){
window.exitConnection();
}, false);
window.startConnection = function(event){
window.webSocket = new WebSocket(wsServerUrl);
window.webSocket.onopen = function(event){
window.document.getElementById("view_field").innerHTML =
'<p>Success to connect WebSocket Server via SecureWS!</p>'
};
window.webSocket.onmessage = function(event){
alert(event.data);
window.document.getElementById("view_field").innerHTML =
'<p>Server: ' + event.data + '</p>'
};
window.webSocket.onerror = function(error){
document.getElementById("view_field").innerHTML =
'<p>WebSocket Error: ' + error + '</p>';
};
window.webSocket.onclose = function(event){
if(event.wasClean){ //切断が完全に完了したかどうかを確認
document.getElementById("view_field").innerHTML =
'<p>切断完了</p><dl><dt>Close code</dt><dd>' +
event.Code +
'</dd><dt>Close Reason</dt><dd>' +
event.reason +
'</dd></dl>';
webSocket = null;
}
else
document.getElementById("view_field").innerHTML =
'<p>切断未完了</p>';
};
}
window.exitConnection = function(event){
if(window.webSocket != null)
window.webSocket.close(1000, '通常終了'); //onclose関数が呼ばれる
}
window.sendMessage = function(sendingMessage){
if(window.webSocket != null)
window.webSocket.send(sendingMessage);
}