[Solved] Flask: Use SocketIO to implement WebSocket and front-end Vue for real-time push (gevent-websocket, flask-socketio, flask does not have the problem of running on 127..)

Foreword

This article aims to record the problem that the WebSocket always fails to connect to the front-end Vue in the process of using the Flask framework and the front-end cannot get data. And after using the library package gevent-websocket with WebSocket related functions, after running the Flask project, the console does not display the problem of running on 127.0.0.1:5000, and the problem of not outputting log records, and always reporting an error Websocket connection to’ ws://127.0.0.1:5000/socket.io/?EIO=4 & amp;transport=websocket’ failed: Error during Websocket handshake: Unexpected response code: 400′ problem! This article took the author and my classmates a lot of energy and time, please indicate the source for reprinting!

As shown in the figure below: there are only three lines of console output records, always reporting an error (there is no solution for this error on the Internet), etc.

Technology selection: front-end Vue, back-end Flask.

Core issues

It should be noted that there is a native Websocket writing method in the Flask framework, and there is also a SocketIO writing method for the dependency package after Websocket packaging, so in the process of connecting with the front-end, it is necessary to connect with the front-end interface standards. In this project, the back-end was originally written using socketio encapsulated with WebSocket, while the front-end used the native websocket-vue writing method, which resulted in the inability to connect and obtain data. As well as all the error reports or various bug issues, the author speculates that it is related to the gevent-websocket package.

After the front end was changed to vue-socketio, the connection failure problem was successfully resolved. (You can also use the native writing method on the back end. In short, both sides need to use a standard at the same time.) For the front-end Vue, you can refer to the Vue documentation to see which writing method to use.

Flask’s native WebSocket (flask-sockets) and encapsulated SocketIO

The main difference between Flask-Sockets and Flask-SocketIO is that the former only wraps the WebSocket protocol (by using the gevent-websocket project), so it only works with browsers that natively support the WebSocket protocol, for those that do not support the WebSocket protocol. Older browsers can no longer use it.

Flask-SocketIO is different, it not only implements the WebSocket protocol, but also can achieve the same effect for those older browsers that do not support the WebSocket protocol. Both new and old browsers can use it. It can be understood that flask encapsulates the websocket function in the new package socketio.

Another difference is that Flask-SocketIO implements the messaging protocol exposed by the SocketIO Javascript library.
While Flask-Sockets just implement the communication channel, what is sent is completely up to the application.

1, Flask-SocketIO (package writing)

Before using SocketIO, you need to import this package, that is, pip install flask-socketio. It is also possible to import the two functions in this package directly in the code.
That is: from flask_socketio import SocketIO, emit.

The following is the server-side code: (For how to apply it in actual combat, you can see the author’s last article about the code implementation in the flask blog. The general idea is to use threads)

from flask import Flask, render_template
from flask_socketio import SocketIO, emit

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)

@app.route('/')
def index():
    return render_template('index.html')

@socketio.on('my event', namespace='/test')
def test_message(message):
    emit('my response', {<!-- -->'data': message['data']})

@socketio.on('my broadcast event', namespace='/test')
def test_message(message):
    emit('my response', {<!-- -->'data': message['data']}, broadcast=True)

@socketio.on('connect', namespace='/test')
def test_connect():
    emit('my response', {<!-- -->'data': 'Connected'})

@socketio.on('disconnect', namespace='/test')
def test_disconnect():
    print('Client disconnected')
 


if __name__ == '__main__':
    socketio.run(app)

For js, the client code is very simple, go directly to the code: (note that it is the standard of socketio)

$(document).ready(function(){
    var socket = io.connect('http://' + document.domain + ':' + location.port + '/test');
    //Note that if you use the writing method of var socket = io.connect(location.protocol + '//' + document.domain..... ws is encapsulated, which eventually leads to the http protocol.
    ///test in the above code is namespace
    
    socket.on('my response', function(msg) {
        $('#log').append('<p>Received: ' + msg.data + '</p>');
    });.
    
    $('form#emit').submit(function(event) {
        socket.emit('my event', {data: $('#emit_data').val()});
        return false;
    });
    
    $('form#broadcast').submit(function(event) {
        socket.emit('my broadcast event', {data: $('#broadcast_data').val()});
        return false;
    });
});

2, Flask-Sockets (native Websocket writing)

Server:

from flask import Flask
from flask_sockets import Sockets
import datetime
import time
import random

app = Flask(__name__)
sockets = Sockets(app)

@sockets.route('/echo')
def echo_socket(ws):
    while not ws.closed:
        now = datetime.datetime.now().isoformat() + 'Z'
        ws.send(now) #Send data
        time.sleep(1)

@app.route('/')
def hello():
    return 'Hello World!'

if __name__ == "__main__":
    from gevent import pywsgi
    from geventwebsocket.handler import WebSocketHandler
    server = pywsgi.WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
    print('server start')
    server.serve_forever()

Client code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.2.0/jquery.js"></script>
</head>
<body>
    <div id="time" style="width: 300px;height: 50px;background-color: #0C0C0C;
    color: white;text-align: center;line-height: 50px;margin-left: 40%;font-size: 20px"></div>

    <script>
            var ws = new WebSocket("ws://127.0.0.1:5000/echo"); #Connect server
//This is the front-end native writing method of websocket, which directly connects to ws.
            ws.onmessage = function (event) {<!-- -->
                content = document.createTextNode(event.data); # Receive data
                $("#time").html(content);

            };

    </script>
    </body>
</html>

3, Bug 1: There is no Running on 127.0.0.1 and no output log in the console output

After the package of gevent-websocket is installed, the package of gevent will be installed by the way. It should be noted that the package of gevent will cause the bug of running on and no log output log to be output to the console after the project is run.

After verification by the author, I found that the package gevent-websocket is too old, and it has stopped updating in 2017. So if this package is used, it will cause some compatibility issues with the new version of Flask, which leads to the existence of the above two bugs in the console.

Solution: Delete the two packages, gevent and gevent-websocket, and download the simple-websocket package to replace these two packages to complete function development.

After the solution, the console can be displayed normally.

3, Bug 2: Display connection error.

After the connection error, it is speculated that this kind of error of reporting 4 (all errors on the Internet are 3 errors), it should be that the gevent-websocket package is not installed, but it will cause the first type of bug after installation, so you can directly install simple-websocket this dependency package.

Reference article: https://www.cnblogs.com/wangkun122/articles/9117882.html