前言:css
- 爲何我要使用 flask-socketio模塊,而不是flask-sockets?html
- 由於flask-socketio與前端流行的websocket庫socketio語法相似,先後端交互容易理解,而且flask-socketio能很是容易得與flask項目結合。前端
效果預覽:python
後端數字更改,自動推送到前端jquery
1.安裝 flask-socketioweb
pip install flask-socketio
2.項目結構sql
myproject/ |-- env/ |-- <python虛擬環境> |-- report/ <項目的模塊名稱>
|-- api_1/ <接口藍圖>
|-- __init__.py
|-- views.py |-- main/ <前端藍圖> |-- __init__.py |-- views.py <路由和視圖函數文件> ----------------------------------> 要增長websocket相關代碼 |-- forms.py <表單類文件, wtforms插件必須項> |-- templates <HTML模板> |-- static <靜態文件夾>
|-- index.html <前端頁面> ------------------------------------> 要增長websocket相關代碼 |-- XXXXXX/ <其它藍圖> |-- __init__.py ----------------------------------------------------> 要增長websocket相關代碼 |-- models.py <數據庫模型文件> |-- migrations/ <數據庫表關係文件夾,Flask-Migrate遷移數據庫時使用> |-- config.py <項目的配置文件> |-- manage.py <用於啓動程序以及其它程序任務> --------------------------------> 要增長websocket相關代碼
3.修改代碼數據庫
1) 修改 myproject/report/__init__.pyjson
# encoding: utf-8 from flask import Flask from flask_mail import Mail from flask_moment import Moment from flask_sqlalchemy import SQLAlchemy from config import config from flask_restful import Api from flask_cors import CORS # 解決跨域請求 from flask_jwt_extended import JWTManager from 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# 爲了不循環引用問題,在這裏導入 # 初始化app def 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.pyflask
# encoding: utf-8 import os from flask_script import Manager from report import app_create from flask_migrate import Migrate, MigrateCommand from report import db, socketio # 新添加代碼 app = app_create(os.getenv('FLASK_CONFIG') or 'default') # 設置啓動方式,可選:development、testing、production manager = 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 upgrade manager.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-8 import re import requests from . import main from flask import render_template,redirect, url_forfrom report import socketio import time from flask_socketio import emit # 新加入的代碼 from threading import Lock import random # 新加入的代碼-開始 thread = None thread_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是接收消息
<!doctype html> <html> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <title>xxx</title> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 引入css文件 start--> <link href="https://cdn.bootcss.com/bootstrap/4.1.0/css/bootstrap.css" rel="stylesheet"> <!-- 引入css文件 end--> </head> <body style="margin: 0 auto"> <div class="container"> <div class="row"> <div style="margin-bottom: 5%" class="col-md-12 text-center head-title-font"> <button id="auto_num" class="btn btn-primary" style="width: 10%"></button> </div> </div> </div> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.slim.js"></script> <!-- 新添加代碼 start --> <script src="https://cdn.bootcss.com/socket.io/2.1.1/socket.io.dev.js"></script> <script> var socket = io('http://127.0.0.1:5000/websocket/user_refresh');--------------------------> 後臺接口 socket.on('connect', function() { // 發送到服務器的通訊內容 socket.emit('connect_event', {data: '我已鏈接上服務端!'}); }); socket.on('server_response', function(msg) { //顯示接受到的通訊內容,包括服務器端直接發送的內容和反饋給客戶端的內容 console.log(msg); }); socket.on('user_response', function(msg) { // 獲取後端傳過來的業務數據 var obj = eval(msg.data[0]); console.log(obj); $("#auto_num").empty(); $("#auto_num").append(obj['name']); }); </script>
<!-- 新添加代碼 end -->
</body> </html>
4. 項目啓動
在項目目錄下,執行:
python manage.py runserver
或者與gunicorn、uWSGI等結合使用。