【问题标题】:Flask-SocketIO access session from background task来自后台任务的 Flask-SocketIO 访问会话
【发布时间】:2022-01-14 21:14:43
【问题描述】:

我有一个 Flask 应用程序,用于使用 gevent 在客户端和服务器之间进行 http 和 Web 套接字 (Flask-SocketIO) 通信。我还为应用程序使用带有 Flask-Session 扩展的服务器端会话。我使用 SocketIO.start_background_task 运行后台任务。从这个任务中,我需要访问会话信息,这些信息将用于使用 socketio 发出消息。从任务"RuntimeError: Working outside of request context." This typically means that you attempted to use functionality that needed an active HTTP request.访问会话时出错

Socket IO 实例的创建如下- socket_io = SocketIO(app, async_mode='gevent', manage_session=False)

这种用法有什么问题吗?如何解决这个问题?

谢谢

【问题讨论】:

    标签: flask python-3.8 flask-socketio flask-session


    【解决方案1】:

    这与 Flask-SocketIO 无关,而是与 Flask 有关。您启动的后台任务没有请求和应用程序上下文,因此它无权访问会话(它甚至不知道客户端是谁)。

    Flask 提供 copy_current_request_context 装饰器将请求/应用上下文从请求处理程序复制到后台任务中。

    Flask 文档中的示例使用gevent.spawn() 来启动任务,但对于以start_background_task() 启动的任务来说也是如此。

    import gevent
    from flask import copy_current_request_context
    
    @app.route('/')
    def index():
        @copy_current_request_context
        def do_some_work():
            # do some work here, it can access flask.request or
            # flask.session like you would otherwise in the view function.
            ...
        gevent.spawn(do_some_work)
        return 'Regular response'
    

    【讨论】:

    • 感谢您的快速回复和解决方案。如果在后台任务中修改了会话数据,这将需要在实际上下文中进行更新,这是否可以进一步改进并且可能没有本地功能?
    • 您在后台任务中对会话所做的更改不会被保留。要保留对会话的更改,您需要使用更新的会话 cookie 向客户端返回响应。这在后台任务中是不可能的,因为等待响应的客户端没有未完成的请求。例如,您可以推迟对会话的更改,直到客户端请求后台任务的状态并且任务完成时。在这种情况下,您可以将新的会话数据与状态请求的响应一起发送。