0
私はAPIを持っています。要求プロトコルによっては、クライアントにHTTP応答を提供するか、websocketと応答の後に増分更新を送信します。しかし、Tornadoでは、どのURLに対しても単一のハンドラしか指定できません。竜巻の同じURLにあるHTTPページとWebSocketをどうすればいいのですか?
私はAPIを持っています。要求プロトコルによっては、クライアントにHTTP応答を提供するか、websocketと応答の後に増分更新を送信します。しかし、Tornadoでは、どのURLに対しても単一のハンドラしか指定できません。竜巻の同じURLにあるHTTPページとWebSocketをどうすればいいのですか?
HTTPページとWebソケットの要求の違いは、ヘッダーが存在することです。残念ながらafaikには、竜巻ルーターにヘッダー(ホスト以外)に基づいて1つまたは他のハンドラーを選択させる方法がありません。
しかし私はすでにかなり精巧なMyBaseRequestHandler
とWebSocketHandler
の両方を継承し、いくつかの魔法を使ってハンドラを作ることができます。次のコードはpython 3.5とtornado 4.3で動作しますが、あなたの走行距離は他のバージョンと異なる場合があります:
class WebSocketHandlerMixin(tornado.websocket.WebSocketHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# since my parent doesn't keep calling the super() constructor,
# I need to do it myself
bases = type(self).__bases__
assert WebSocketHandlerMixin in bases
meindex = bases.index(WebSocketHandlerMixin)
try:
nextparent = bases[meindex + 1]
except IndexError:
raise Exception("WebSocketHandlerMixin should be followed "
"by another parent to make sense")
# undisallow methods --- t.ws.WebSocketHandler disallows methods,
# we need to re-enable these methods
def wrapper(method):
def undisallow(*args2, **kwargs2):
getattr(nextparent, method)(self, *args2, **kwargs2)
return undisallow
for method in ["write", "redirect", "set_header", "set_cookie",
"set_status", "flush", "finish"]:
setattr(self, method, wrapper(method))
nextparent.__init__(self, *args, **kwargs)
async def get(self, *args, **kwargs):
if self.request.headers.get("Upgrade", "").lower() != 'websocket':
return await self.http_get(*args, **kwargs)
# super get is not async
super().get(*args, **kwargs)
class MyDualUseHandler(WebSocketHandlerMixin, MyBaseHandler):
def http_get():
self.write("My HTTP page")
def open(self, *args, **kwargs):
self.write_message("Hello WS buddy")
def on_message(self, message):
self.write_message("I hear you: %s" % message)