Flask: API RESTful и сервер SocketIO

Фон

Я пытаюсь создать простой REST API с помощью расширения Flask-RESTful. Этот API будет работать в первую очередь для управления CRUD и аутентификации пользователей для простой службы.

Я также пытаюсь создать несколько веб-сокетов с помощью расширения Flask-SocketIO, к которому эти пользователи смогут подключаться и видеть обновления в режиме реального времени для некоторых данных, связанных с другими людьми, использующими службу. Таким образом, мне нужно знать, что эти пользователи аутентифицированы и имеют право подключаться к определенным сокетам.

Проблема

Однако у меня возникли проблемы с настройкой. Похоже, я не могу заставить эти два компонента (REST API и сервер SocketIO) работать вместе в одном экземпляре Flask. Причина, по которой я говорю это, заключается в том, что, когда я запускаю следующее, либо REST API, либо сервер SocketIO будут работать, но не оба:

from flask import Flask
from flask_restful import Api
from flask.ext.socketio import SocketIO

app = Flask(__name__)

api = Api(app)
socketio = SocketIO(app)

# some test resources for the API and
# a test emitter statement for the SocketIO server
# are added here

if __name__ == '__main__':
    app.run(port=5000)
    socketio.run(app, port=5005)

Вопрос

Является ли типичное решение для этого типа установки одновременным запуском двух разных экземпляров Flask? Например, должен ли мой сервер SocketIO делать запросы к моему REST API, чтобы убедиться, что конкретный пользователь аутентифицирован / авторизован для подключения к определенному сокету?


person nmagerko    schedule 13.09.2015    source источник
comment
Что произойдет, если вы просто используете socketio.run(app, port=5005) и попытаетесь задействовать REST API на порте 5005?   -  person Sean Vieira    schedule 13.09.2015
comment
@SeanVieira По какой-то причине это работает нормально ... Полагаю, я просто сохраню свой API и сокеты на том же порту, тогда   -  person nmagerko    schedule 13.09.2015


Ответы (1)


Вам просто нужно запустить socketio.run(app, port=5005) и нажать REST API на порте 5005.

Причина, по которой это работает, заключается в том, что под капотом Flask-SocketIO запускает веб-сервер с четкостью на основе gevent (или с выпуском 1.0, также eventlet) - этот сервер напрямую обрабатывает запросы веб-сокетов (с использованием обработчиков, которые вы регистрируете с помощью декоратора socketio.on) и передает запросы, не связанные с веб-сокетами, во Flask.

Причина, по которой ваш код не работает, заключается в том, что и app.run, и socketio.run являются блокирующими операциями. Какой бы из них ни запускался первым, он зацикливался, ждал соединений, не позволяя второму сработать. Если вам действительно нужно запускать подключения к веб-сокету на другом порту, вам нужно будет запустить вызов socketio или приложения run в другом процессе.

person Sean Vieira    schedule 13.09.2015
comment
Отличный ответ, но я хотел отметить, что Flask-SocketIO вот-вот сломает исключительную зависимость от gevent. Версия 1.0a1 для разработки расширения может использовать gevent, eventlet или даже простой Werkzeug (хотя последний работает без поддержки WebSocket). - person Miguel; 13.09.2015