前言:
- 为什么我要使用 flask-socketio模块,而不是flask-sockets?
- 因为flask-socketio与前端流行的websocket库socketio语法类似,前后端交互容易理解,并且flask-socketio能非常容易得与flask项目结合。
效果预览:
后端数字更改,自动推送到前端
1.安装 flask-socketio
pip install flask-socketio
2.项目结构
myproject/|-- env/ |--|-- report/ <项目的模块名称> |-- api_1/ <接口蓝图> |-- __init__.py |-- views.py |-- main/ <前端蓝图> |-- __init__.py |-- views.py <路由和视图函数文件> ----------------------------------> 要增加websocket相关代码 |-- forms.py <表单类文件, wtforms插件必须项> |-- templates |-- static <静态文件夹> |-- index.html <前端页面> ------------------------------------> 要增加websocket相关代码 |-- XXXXXX/ <其它蓝图> |-- __init__.py ----------------------------------------------------> 要增加websocket相关代码 |-- models.py <数据库模型文件> |-- migrations/ <数据库表关系文件夹,flask-migrate迁移数据库时使用> |-- config.py <项目的配置文件> |-- manage.py <用于启动程序以及其它程序任务> --------------------------------> 要增加websocket相关代码 用于启动程序以及其它程序任务> 项目的配置文件> 数据库表关系文件夹,flask-migrate迁移数据库时使用> 数据库模型文件> 其它蓝图> 前端页面> 静态文件夹> 表单类文件,> 路由和视图函数文件> 前端蓝图> 接口蓝图> 项目的模块名称>
3.修改代码
1) 修改 myproject/report/__init__.py
# encoding: utf-8from flask import Flaskfrom flask_mail import Mailfrom flask_moment import Momentfrom flask_sqlalchemy import SQLAlchemyfrom config import configfrom flask_restful import Apifrom flask_cors import CORS # 解决跨域请求from flask_jwt_extended import JWTManagerfrom flask_socketio import SocketIO # 新添加的代码mail = Mail()moment = Moment()db = SQLAlchemy()api = Api()async_mode = None # 新添加的代码socketio = SocketIO() # 新添加的代码from report.api_1.views import ServiceCheckApi, GetRecordData# 为了避免循环引用问题,在这里导入# 初始化appdef app_create(config_name): app = Flask(__name__) app.config.from_object(config[config_name]) config[config_name].init_app(app) mail.init_app(app) moment.init_app(app) db.init_app(app) jwt = JWTManager(app) # 路由和其他处理程序定义 # 注册蓝图 from .main import main as main_blueprint # 从当前目录下面的main子目录中导入main对象 app.register_blueprint(main_blueprint) api.add_resource(ServiceCheckApi, '/api/service_check') # api与websocket无关 api.add_resource(GetRecordData, '/api/get_data') # add_resource 函数使用指定的endpoint 将路由注册到框架上 api.init_app(app) # api初始化必须放在路由注册之后 CORS(app) # 跨域请求 socketio.init_app(app=app, async_mode=async_mode) # 新添加的代码 return app
2) 修改 myproject/manage.py
# encoding: utf-8import osfrom flask_script import Managerfrom report import app_createfrom flask_migrate import Migrate, MigrateCommandfrom report import db, socketio # 新添加代码app = app_create(os.getenv('FLASK_CONFIG') or 'default') # 设置启动方式,可选:development、testing、productionmanager = Manager(app)migrate = Migrate(app, db) # 使用Migrate将app与db关联# 自定义命令 ,# 在命令行使用: python manage.py runserver# @manager.command# def runserver():# print('running')# 添加额外二级命令# 第一种方式:自定义命令# manager.add_command('db',DBmanager) # 'db'是自定义的命令名字# 在命令行使用: python manage.py db init ,init是自定义的函数# 第二种方式:数据迁移使用MigrateCommand中自带的命令(常用)# 该模块中带有的命令的使用顺序(顺序不能乱):# python manage.py db init# python manage.py db migrate# python manage.py db upgrademanager.add_command('db', MigrateCommand)manager.add_command('run', socketio.run(app=app, host='0.0.0.0', port=5000)) # 新加入的代码,重写manager的run命令if __name__ == '__main__': manager.run()
3)修改 myproject/report/main/views.py
# encoding: utf-8import reimport requestsfrom . import mainfrom flask import render_template,redirect, url_forfrom report import socketioimport timefrom flask_socketio import emit # 新加入的代码from threading import Lockimport random# 新加入的代码-开始thread = Nonethread_lock = Lock()def background_thread(users_to_json): """Example of how to send server generated events to clients.""" while True: print(users_to_json) users_to_json = [{'name': '王腾' + str(random.randint(1, 100))}] socketio.sleep(0.5) # 每五秒发送一次 socketio.emit('user_response', {'data': users_to_json}, namespace='/websocket/user_refresh')@socketio.on('connect', namespace='/websocket/user_refresh')def connect(): """ 服务端自动发送通信请求 """ global thread user_to_json = '' with thread_lock: if thread is None: thread = socketio.start_background_task(background_thread, (users_to_json, )) emit('server_response', {'data': '试图连接客户端!'})@socketio.on('connect_event', namespace='/websocket/user_refresh')def refresh_message(message): """ 服务端接受客户端发送的通信请求 """ emit('server_response', {'data': message['data']})# 新加入的代码-结束@main.route('/', methods=['GET'])def index(): return render_template('index.html')
4)修改myproject/report/main/templats/index.html
需要注意到是:
server_response、
user_response、
connect、
connect_event 这几个自定义事件在前后端的对应关系。emit是发送消息,on是接收消息
xxx
4. 项目启动
在项目目录下,执行:
python manage.py runserver
或者与gunicorn、uWSGI等结合使用。