I have a Flask server-app/React client-app into which I am trying to integrate flask_socketio. I have replicated the standard introductory example from the flask_socketio docs and it works fine with my React front-end.
However, when I try to replicate the results in flask, using the exact same steps I cannot send or receive messages. I can see a client has connected in the output when I run my flask app, and in the browser console I have a console.log telling me I am connected to the server, but emit (or send) don't seem to work the way the intro example did.
I have eventlet installed, and the docs say that flask_socketio should recognize this automatically. Here are some code snippets for reference.
app/socket/__ init __.py
from flask_socketio import SocketIO
socketio = SocketIO(cors_allowed_origins='http://localhost:3000')
app/socket/socket.py
from flask_cors import cross_origin
from flask_socketio import send, emit
from . import socketio
#cross_origin
#socketio.on('connect')
def handle_connection():
print('a user has connected')
emit('mymessage', 'Hi client, I am server.') # I've tried `send` here too
#cross_origin
#socketio.on('mymessage')
def handle_message(message):
print('Message from client: ' + message)
app/__ init __.py
from flask import Flask
from flask_cors import CORS
from .socket import socketio
def create_app():
app = Flask(__name__)
# Cross Origin Resource Sharing
CORS(app)
# Socket.IO
socketio.init_app(app)
return (socketio, app)
app/app.py
from . import create_app
socketio, app = create_app()
if __name__ == '__main__':
socketio.run(app, host='localhost', port=5000)
#app.run("0.0.0.0", port=5000, threaded=True, use_reloader=False)
React component
const socket = io('http://localhost:5000');
class Figures extends React.Component {
setSocketListeners () {
socket.on('connect', () => {
console.log('connected to socket');
socket.emit('mymessage', 'Hi server, I am client.');
})
socket.on('mymessage', function(data) {
console.log('Message from server: ' + data)
})
}
componentDidMount() {
this.setSocketListeners()
}
...
Output:
terminal
* Restarting with stat
* Debugger is active!
* Debugger PIN: 216-814-307
(4089) wsgi starting up on http://127.0.0.1:5000
127.0.0.1 - - [14/Aug/2019 02:40:35] "POST /socket.io/?EIO=3&transport=polling&t=MoEsrSZ&sid=a4f73c34553f478cabde2f919b48fe98 HTTP/1.1" 200 219 0.002675
(4089) accepted ('127.0.0.1', 36512)
(4089) accepted ('127.0.0.1', 36514)
127.0.0.1 - - [14/Aug/2019 02:40:36] "GET /socket.io/?EIO=3&transport=polling&t=MoEsrSf&sid=a4f73c34553f478cabde2f919b48fe98 HTTP/1.1" 200 235 1.612156
browser
connected to socket
EDIT:
Preliminary debugging seems to suggest this is some issue with 'create_app()'. See link from #miguelgrinberg. Still no progress on how to fix the issue though.
Have enabled socketio.init_app(app, async_mode="eventlet", engineio_logger=True) and disabled debugging in flask to make sure werkzeug isn't being used.
A similar issue was related here
I think you should enable transport mode to WebSocket when opening socket on your frontend code, something like:
const socket = io('http://localhost:5000', {transports: [websocket]});
Also you need to install gevent and gevent-websocket and import socket.io-client like:
import io from 'socket.io-client/dist/socket.io';
I've implemented a working example: https://github.com/roj4s/webicami
Related
I am trying to transition from making Rshiny apps to flask-react apps. Its definitely a steep learning curve so far!
I am sort of following a few tutorials e.g (https://dev.to/arnu515/build-a-fullstack-twitter-clone-using-flask-and-react-1j72) to try and get some basic functionality down .
However some reason curl can't seem to interact with my app. I've tried putting the urls with and without quotes but get the same response. Also I tried the default 5000 port as well. I am running the app in windows:
C:\Users\Marc\flaskTest\backend>curl "http://127.0.0.1:5500"
curl: (7) Failed to connect to 127.0.0.1 port 5500: Connection refused
app.py code
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
#app.route('/')
def index():
return "hello"
#app.route('/message', methods=["GET"])
def message():
message ="my message"
return jsonify({"message": message})
if __name__ == "__main__":
app.run(debug=True, port=5500)
You used jsonify in the view function but haven't imported it before, so there would be error when Flask app runs.
Actually you can just write code like return {"message": message}, it would do the same thing with jsonify does if you are using latest version of flask.
Try:
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, port=5500)
Also in windows cmd type ipconfig IPV4 address. Suppose your IPV4 address is 192.168.X.X, access the website as http://192.168.X.X:5500.
Read what it does: Externally Visible Server
I deployed the flask application on Heroku.
application.py contents:
import os
from flask import Flask, render_template
from flask_socketio import SocketIO, emit, join_room, leave_room
app = Flask(__name__)
socketio = SocketIO(app)
#my stuff
if __name__ == '__main__':
socketio.run(app)
requirements.txt contents:
Flask
Flask-SocketIO
gunicorn
eventlet
Procfile contents:
web: gunicorn -k eventlet application:app
client JS code contents:
document.addEventListener("DOMContentLoaded", () => {
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port);
The application runs, I can see its front-end. But the browser sends the alert: Error: xhr post error
In console I see:
socket.io.min.js:2 WebSocket connection to 'wss://.....herokuapp.com/socket.io/?EIO=3&transport=websocket&sid=0838a049bc124fc18c320fd489ff1935' failed: WebSocket is closed before the connection is established. n.doClose # socket.io.min.js:2
socket.io.min.js:1 POST https://......herokuapp.com/socket.io/?EIO=3&transport=polling&t=1583010125065-6&sid=442aedb87e2741968afca2574386ce30 400 (BAD REQUEST)
Could you please give an advice where I am going wrong?
Thanks!
Basically, I have a socket io flask code:
import cv2
import numpy as np
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
from threading import Lock,Timer as tmr
from engineio.payload import Payload
import base64
from PIL import Image
import io
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
#socketio.on('connect')
def connect():
print("a client connected")
#socketio.on('disconnect')
def disconnect():
print('Client disconnected')
#app.route('/')
def hello():
return render_template('index.html')
if __name__ == '__main__':
socketio.run(app,port=port,host= '0.0.0.0')
This code is working fine when I try to connect it to javascript
However in flutter I can not achieve that
I have stateful Widget that has a button in it
And I am using this function to connect to my socket when the button is pressed
import 'package:socket_io_client/socket_io_client.dart' as IO;
IO.Socket socket;
connectToSocket() {
socket = IO.io("http://10.0.2.2:6400", <String, dynamic>{
'transports': ['websocket', 'polling'],
});
socket.connect();
}
I can not connect it please help me.
I know this is an older question but hopefully this answer will help someone down the road.
The issue may be caused by the lack of support for polling in flutter.
from: https://github.com/rikulo/socket.io-client-dart#usage-flutter
In Flutter env. it only works with dart:io websocket, not with dart:html websocket, so in this case you have to add 'transports': ['websocket'] when creates the socket instance.
IO.Socket socket = IO.io('http://localhost:3000', <String, dynamic>{
'transports': ['websocket'],
'extraHeaders': {'foo': 'bar'} // optional
});
The default Flask development server doesn't support websockets so you'll need to use another server. Thankfully it's simple to get eventlet working with Flask. All you should have to do is install the eventlet package using pip.
pip install eventlet
Once eventlet is installed socketio will detect and use it when running the server.
You can use chrome to double check what transport method is being used. Open your chrome dev tools Ctrl+Shift+I in Windows and go to the Network tab. On each network request you should see either transport=polling or transport=websocket
I'm using the following code snippet to run WSGIServer in python:
from bottle import request, Bottle, abort
app = Bottle()
.. other stuff ...
from gevent.pywsgi import WSGIServer
from geventwebsocket import WebSocketError
from geventwebsocket.handler import WebSocketHandler
server = WSGIServer(("0.0.0.0", 8080), app,
handler_class=WebSocketHandler)
server.serve_forever()
The server works fine but every time I send a request to this server, there is nothing printed out on console (the way bottle or flask do when you run their server directly). Those console logs would really help me understand what requests the browser is making. I tried inserting debug=True in several places in above code, but none seemed to work. What am I doing wrong ?
I believe you should add this line before starting the server .
app.debug = True
Is it possible to disable nginx's custom error pages - if I may call them that - to display my framework's exception pages?
I can't really see my werkzeug debugger tool rendered in html...
UPDATE
OK, I got to make a very very simple flask application to work and I'll post the bits:
/home/my_user/.virtualenvs/nginx-test/etc/nginx.conf
worker_processes 1;
events { worker_connections 1024; }
http {
server {
listen 5000;
server_name localhost;
access_log /home/my_user/.virtualenvs/nginx-test/lib/nginx/access.log;
error_log /home/my_user/.virtualenvs/nginx-test/lib/nginx/error.log;
location / {
include uwsgi_params;
uwsgi_pass unix:/tmp/uwsgi.sock;
}
}
}
/home/my_user/dev/nginx_test/___init___.py
from flask import Flask
app = Flask(__name__)
#app.route('/')
def index():
raise Exception()
if __name__ == '__main__':
app.run('0.0.0.0', debug=True)
PYTHONPATH environment variable:
$ echo $PYTHONPATH
/home/my_user/dev/
How I run uwsgi:
$ uwsgi -s /tmp/uwsgi.sock --module nginx_test --callable app
How I run nginx:
$ nginx -c ~/.virtualenvs/nginx-test/etc/nginx.conf -p ~/.virtualenvs/nginx-test/lib/nginx/
If I hit the root page:
If I run nginx manually like:
python /home/my_user/dev/nginx_test/___init___.py
I will see instead, and what I want to see:
Of course I made sure it would work when I didn't raise the exception, but returned 'Hello World' for example on my index() function.
This is referred to custom error pages in .NET. I want to disable this and let nginx/uwsgi pass the html generated by the debugger directly to the browser instead of the internal server error thing.
UPDATE 2
Now if I change my flask app to enable debugging mode by:
/home/my_user/dev/nginx_test/___init___.py
from flask import Flask
app = Flask(__name__)
app.config.update(DEBUG=True)
#app.route('/')
def index():
raise Exception()
if __name__ == '__main__':
app.run('0.0.0.0', debug=True)
Then I get 502 error.
But if I instead of raise Exception:
/home/my_user/dev/nginx_test/___init___.py
from flask import Flask
app = Flask(__name__)
app.config.update(DEBUG=True)
#app.route('/')
def index():
return 'Hello World'
if __name__ == '__main__':
app.run('0.0.0.0', debug=True)
I get 'Hello World' on my browser when I hit the page (http://localhost:5000).
This "Internal Server Error" page is not from nginx but from Flask. It does so when debug mode is off.
uwsgi is importing your code as a module, not running at as a script. __name__ == '__main__' is False and the if statement is not executed. Try setting debug mode outside of the if:
app = Flask(__name__)
app.debug = True
However, it is strongly recommended to never leave the debug mode on a server on the public internet, since the user can make the server run any code. This is a serious security issue.
Use Flask#errorhandler to register your own error handlers in flask. For example to replace the 404 you would do something like:
app = Flask()
#app.errorhandler(404)
def handel_404(error):
return render_template('404.html')
Simon Sapin has really given you the correct answer. You need to enable debug in Flask. Nginx does not return any custom error pages unless you explictly configure it to do so.
If you use the following code you will see your debug messages from flask, proxied via Nginx.
from flask import Flask
app = Flask(__name__)
app.debug = True
#app.route('/')
def index():
raise Exception()
As per your update 2. You are seeing a 502 (bad gateway) because Flask is simply not returning any response at all, or a response that Nginx does not understand. A 502 is not a problem with Nginx. It means that whatever Nginx is trying to talk (your flask app in this case) is not working properly at all.
However, in many ways you shouldn't be doing this. Debugging mode should only be enabled when you are running flask on your local dev machine. Which is the whole point of the if __name__ == "__main__": line anyway.