gevent-socketio 没有使用我的 @app.route 端点进行 socketio

Posted

技术标签:

【中文标题】gevent-socketio 没有使用我的 @app.route 端点进行 socketio【英文标题】:gevent-socketio not using my @app.route endpoint for socketio 【发布时间】:2013-08-21 13:51:07 【问题描述】:

我将 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) 
    ...
)

【问题讨论】:

同时发布客户端代码 添加了客户端代码。 如果您在调用 connect 时收到 /socket.io/1/,则说明您做错了。 Connect 应该通过 POST 调用到 /socket.io/1/。通过省略下一段,您正在启动一个新的连接。因此,您要么已连接,并且最后收到带有“stuff”的响应,这意味着它有效 - 或者您启动连接错误。现在,如果它正在工作并且没有调用您的代码,您确定您正确初始化了您的命名空间吗? gevent-socketio.readthedocs.org/en/latest/namespace.html 问题是我应该拦截socket.io调用以注册我的命名空间的函数从未被调用。将 POST 添加为允许的方法并没有帮助,因为 SocketIOServer 会在 /socket.io* 的请求甚至到达 WSGI 应用程序之前拦截它们。 【参考方案1】:

奇怪的行为是因为这行:

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 调用中。请注意,我没有考虑太多,可能还有其他问题。

【讨论】:

谢谢!我以为我已经尝试过了,但我想我做错了,因为这次它奏效了。【参考方案2】:

花了我一段时间,但看起来我已经解决了,享受吧:

https://github.com/Aldanor/SocketIO-Flask-Debug

简而言之:

您需要在发现 socket.io 请求时从 werkzeug.debug.DebuggedApplication 返回的生成器中显式提取值,这样才能正确建立套接字连接 默认情况下 werkzeug 不会覆盖 socket.io 命名空间处理程序,因此您需要插入自己的 try catch,如果捕获到异常则保存回溯,然后在请求上下文中的某处重新引发它

【讨论】:

不要回答链接。在这里解释如何解决问题。阅读常见问题解答了解更多信息。 我只是想帮助其他人(考虑到我自己在这个问题上的挣扎)。上面的链接包含一个带有完整文档代码的工作示例,它有什么问题?无论如何,更新了答案。

以上是关于gevent-socketio 没有使用我的 @app.route 端点进行 socketio的主要内容,如果未能解决你的问题,请参考以下文章

gevent-socketio 从线程发送消息

使用 gevent-socketio 和 Socket.IO.js 的 Python 瓶子微框架的最小示例

python.h 在尝试安装 gevent-socketio 时不喜欢

使用 Python3 在 Pyramid 中使用 Websocket

使用一个服务器进程从 Django 应用程序推送通知

如何在我的桌面(Windows 7)上使用我的python程序在没有notify2,notify-send,pqt5的桌面上显示简单的通知?