Python Flask
WebSocket Socket.IO
▌Introduction
In previous article, [Flask] Socket.IO
integration : Flask-SocketIO, we had successfully create Websocket by Flask-SocketIO on our Flask
application.
If you are a Vue.js developer like me, you may want to
implement the client side with Socket.IO client in Vue way.
Fortunately Metin Seylan has implemented the
open-source project: Vue-Socket.io,
to make it simple and clean.
▌Environment
▋Python 3.6.5
▋Flask 1.0.2
▋Flask-SocketIO 3.1.2
▋Socket.IO 2.2.0
▋Vue.js 2.5.21
▋Vue-Socket.io 3.0.4
▌Implement
▋Server-side
If you followed the previous article’s steps, the
project file’s hierarchy currently is
Now create these files:
app/static/js/index.js
app/templates/index_vue.html
Before we start implementing the them, there are a
few issues here:
1. Flask use “{{“ and “}}” to indicate a server-side variable on template
which will be conflicted with Vue.js
2. How client side (javascript) knows which server url to connect?
To solve the first issue, we will need to modify the default Jinja2 options on variable_start_string
and variable_end_string.
For the second issue, we can assign the value of Flask’s template variable to Vue’s global variable.
▋Update Jinja2 ‘s options
▋main.py
class CustomFlask(Flask):
jinja_options =
Flask.jinja_options.copy()
jinja_options.update(dict(
variable_start_string='%%', # Default is '{{' but Vue.js uses '{{'
/ '}}'
variable_end_string='%%', # Default is
'}}' but Vue.js uses '{{' / '}}'
))
app = CustomFlask(__name__, template_folder='./templates')
Now the template variable must be inside “%%” and “%%”
▋Pass template variable to Vue
▋main.py
When rendering template, pass a template variable: server_addr.
from flask import Flask,
render_template, request, jsonify
from flask_socketio import SocketIO,
emit
# Global variables
SERVER_ADDR = "http://localhost:5000" # default
Server ip/port (local)
app = Flask(__name__, template_folder='./templates')
# Websocket setting
app.config['SECRET_KEY'] = '12qwaszx'
socketio = SocketIO(app)
@app.route('/')
def index():
return render_template('index_vue.html',
async_mode=socketio.async_mode, server_addr=SERVER_ADDR)
On index_vue.html, keep the server_addr’s value to Vue’s global variable
▋index_vue.html
<script lang="javascript">
Vue.prototype.$serverAddr = "%% server_addr %%";
</script>
▋Integrate Vue-Socket.io
First implement the
HTML as following,
▋index_vue.html
<script lang="javascript">
Vue.prototype.$serverAddr = "%% server_addr %%";
</script>
<div id="app">
<div>
<input class="form-control" type="text" v-model="clientMsg" @keyup.enter="emitMsg"/>
<button class="btn
btn-success" id="emitMsg" @click="emitMsg">Send</button>
</div>
<br />
<pre>{{ log }}</pre>
</div>
<script src="%%
url_for('static', filename="js/index.js") %%"> </script>
Then we can enable Vue-Socket.io and
register the event handler:
1. Connect
2. Server_response
▋index.js
Vue.use(new VueSocketIO({
debug: true,
connection: Vue.prototype.$serverAddr //'http://localhost:5000'
}))
var app = new Vue({
el: "#app",
sockets: {
connect: function () {
this.appendLog("Start connect...");
this.$socket.emit('connected_event', { data: 'WebSocket connected successfully.' });
server_response: function (msg) {
this.appendLog(msg.data);
}
},
data: {
clientMsg: "",
log: "",
},
methods: {
emitMsg: function () {
this.$socket.emit('broadcast_event', { data: this.clientMsg
});
},
appendLog: function (newLog) {
this.log +=
newLog + "\n";
}
},
created: function () {
}
})
▋Demo
▋Sample code
▌Reference
沒有留言:
張貼留言