我将Flask与gevent socketio:一起使用
$ cat requirements.txt
Flask==0.10.1
Jinja2==2.7.1
MarkupSafe==0.18
Werkzeug==0.9.3
argparse==1.2.1
gevent==0.13.8
gevent-socketio==0.3.5-rc2
gevent-websocket==0.3.6
greenlet==0.4.1
itsdangerous==0.23
wsgiref==0.1.2
我使用一个非常标准的设置来启动服务器:
#Called from __main__
def run_dev_server():
app.debug = True
port = 5000
dapp = werkzeug.debug.DebuggedApplication(app, evalex = True)
SocketIOServer(('', port), dapp, resource="socket.io").serve_forever()
还有一个相当标准的挂钩,用于我的SocketIO命名空间:
@app.route('/socket.io/<path:rest>')
def push_stream(rest):
print 'ws connect', rest
try:
socketio.socketio_manage(request.environ, {'/join_notification': JoinsNamespace}, request)
except Exception as e:
app.logger.error("Exception while handling socketio connection", exc_info=True)
return flask.Response()
但是,我遇到了客户端上没有触发"连接"事件的问题。经过一番挖掘,我意识到,尽管我在输出中得到了127.0.0.1 - - [2013-08-19 12:53:57] "GET /socket.io/1/websocket/170191232666 HTTP/1.1" 101 - -
消息,但我没有得到ws connect
消息(而代码中的其他打印语句工作正常)。我评论掉了那个端点,当然它甚至没有被调用。这可以解释为什么我的命名空间没有被使用。但为什么呢?我的命名空间注册错了吗?
print app.url_map
产量:
Map([<Rule '/' (HEAD, OPTIONS, GET) -> root>,
<Rule '/socket.io/<rest>' (HEAD, OPTIONS, GET) -> push_stream>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>])
所以没有什么特别的。
编辑:客户端代码:
socket = io.connect('/join_notification')
console.log(socket)
socket.on('connect', function() {
console.log('connected to websocket')
socket.emit('login', {'name': data['name']})
})
socket.on('disconnect', function() {
console.log('d/c'd from websocket')
})
socket.on('join_error', function() {
...
})
socket.on('join_success', function(data){
...
})
socket.on('join', function(data) {
...
})
奇怪的行为是因为这行:
dapp = werkzeug.debug.DebuggedApplication(app, evalex = True)
Socketio和werkzeug调试器不能一起工作。这方面已经存在一个悬而未决的问题,请参阅:https://github.com/abourget/gevent-socketio/issues/114
但是您可以通过创建一个自定义调试器类来解决这个问题。
from werkzeug.debug import DebuggedApplication
class MyDebuggedApplication(DebuggedApplication):
def __call__(self, environ, start_response):
# check if websocket call
if "wsgi.websocket" in environ and not environ["wsgi.websocket"] is None:
# a websocket call, no debugger ;)
return self.app(environ, start_response)
# else go on with debugger
return DebuggedApplication.__call__(self, environ, start_response)
# remember to call the overwritten debugger in your run_dev_server() function
dapp = MyDebuggedApplication(app, evalex = True)
该补丁依赖于环境密钥wsgi.websocket,它似乎只存在于websocket调用中。小心,我还没想太多,可能还有其他问题。
花了我一段时间,但看起来我已经解决了它,享受:
https://github.com/Aldanor/SocketIO-Flask-Debug
简而言之:
- 只要发现socket.io请求,就需要从werkzeug.debug.DebuggedApplication返回的生成器中显式提取值,这样可以正确地建立套接字连接
- 默认情况下,socket.io命名空间处理程序不会被werkzeug覆盖,因此您需要插入自己的try-catch,如果捕获到异常则保存回溯,然后在请求上下文中的某个位置重新评估它