【问题标题】:Flask: Unable to access current_app from within socket.io listenerFlask:无法从 socket.io 监听器中访问 c​​urrent_app
【发布时间】:2013-03-24 12:13:20
【问题描述】:

我正在尝试从侦听器中访问 c​​urrent_app,以便我可以使用应用配置值来订阅哪个频道。但是我收到“RuntimeError:在应用程序上下文之外工作”。

这里是有问题的代码:

from flask import Blueprint, Response, request, current_app
from socketio import socketio_manage
from socketio.namespace import BaseNamespace
from redis import StrictRedis
import pprint

socketapp = Blueprint('socketapp', __name__)


class MessageNamespace(BaseNamespace):
    def listener(self):
        pprint.pprint(current_app.config)
        r = StrictRedis()
        p = r.pubsub()
        p.subscribe('message-channel')

        messages = r.lrange('message', 0, -1)
        self.emit('message-message', ''.join(messages))

        for m in p.listen():
            if m['type'] == 'message':
                self.emit('message-message', m['data'])

    def on_subscribe(self):
        self.spawn(self.listener)


@socketapp.route('/socket.io/<path:remaining>')
def socketio(remaining):
    try:
        socketio_manage(request.environ, {'/messages': MessageNamespace}, request)
    except BaseException:
        pass
    return Response()


@socketapp.route('/message', methods=['GET'])
def say():
    msg = request.args.get('msg', None)
    if msg:
        r = StrictRedis(host=current_app.config['REDIS_HOST'])
        r.rpush('message', msg)
        r.publish('message-channel', msg)

        return Response('Message sent!')
    else:
        return Response('Please specify your message in the "msg" parameter')

【问题讨论】:

  • 你见过这个sn-p - flask.pocoo.org/snippets/105
  • @SeanVieira,您的 sn-p 在命名空间构造函数中使用 current_app,但它不可用。我根据您的代码编写了我的 hack 版本。请查看。

标签: python redis socket.io flask gevent


【解决方案1】:

current_app 仅在处理 HTTP 请求时有效(它是暂时指向实际应用程序对象的代理)。您需要从此模块访问实际的应用程序对象,或者通过current_app._get_current_object() 窃取对它的引用。

【讨论】:

    【解决方案2】:

    Sean 的 sn-p 对我不起作用。我基于它编写了以下 hack:

    @bp.route('/<path:remaining>')
    def socketio(remaining):
        app = current_app._get_current_object()
        try:
            # Hack: set app instead of request to make it available in the namespace.
            socketio_manage(request.environ, {'': ChatNamespace}, app)
        except:
            app.logger.error("Exception while handling socket.io connection", exc_info=True)
        return Response()
    
    
    class ChatNamespace(BaseNamespace, RoomsMixin, BroadcastMixin):
        def __init__(self, environ, ns_name, request=None):
            self.context = None
            if request:
                # Hack: initialize context with app that was set instead of request. Then miss it in parent constructor call.
                app = request
                self.context = app.request_context(environ)
                self.context.push()
                app.preprocess_request()
            super(ChatNamespace, self).__init__(environ, ns_name)
    
    def log(self, message):
            # Now we can access app and other goodies.
            self.context.app.logger.info("[{0}] {1}".format(self.socket.sessid, message))
    
    def disconnect(self, *args, **kwargs):
            if self.context:
                self.context.pop()
            super(ChatNamespace, self).disconnect(*args, **kwargs)
    

    【讨论】:

      猜你喜欢
      • 2022-01-17
      • 2023-03-31
      • 1970-01-01
      • 2017-08-17
      • 2016-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多