I am trying to deploy a Flask Socket.io app on Azure App Services. Locally everything works fine. However, when deploying on Azure I get a 400 code error:
WebSocket connection to
'wss://mydomain.azurewebsites.net/socket.io/?EIO=3&transport=websocket'
failed: Error during WebSocket handshake: Unexpected response code:
400
websockets in Configuration/General Settings/Web
Socket has been enabled
scaled up to B1 pricing tier (this seems to
have solved the problem for some)
My server side looks like this:
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
app.config['DEBUG'] = True
socketio = SocketIO(app,engineio_logger=False,log_output=False,async_mode='eventlet')
#socketio.on('btn_speaker')
def btn_agent(message):
print(message)
agent = message['speaker_msg']
webchat = "speaker says: " + agent
socketio.emit( 'webchat', {'webchat': webchat} )
#app.route('/')
def test():
return render_template('test.html')
if __name__ == '__main__':
socketio.run(app)
and the client:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Socket.io test</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.js"></script>
<script>
$(document).ready(function() {
<!-- var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port); -->
var socket = io({transports: ['websocket']});
$('#btn_speaker').click(function(e) {
socket.emit( 'btn_speaker', {
speaker_msg : $( 'input.speaker' ).val()
} )
$( 'input.speaker' ).val( '' ).focus()
} )
socket.on( 'webchat', function( msg ) {
console.log( msg )
$('#webchat').html(msg.webchat)
})
})
</script>
</head>
<body>
<textarea id="webchat" name="webchat" rows="20" cols="100"></textarea>
<label for="speaker">text:</label>
<input type="text" class="speaker" id="speaker" name="speaker" autocomplete="off">
<button type="submit" id="btn_speaker">Submit speaker</button>
</body>
</html>
requirements.txt:
eventlet
Flask-SocketIO
Two points I had to consider in order to get this to work:
The url needed to be browsed from http (instead from https)
Adding --worker-class eventlet to the gunicorn startup command in Azure enabled browsing and controlling the url from different instances
Related
Hello everyone!,
so I was building a flask app that displays the current time.The time does display on the webpage as intended.But,the thing is that I have the reload the page manually for the time to update.But I want the time to update on itself.Here is my python file containing the code to the website:
from flask_sqlalchemy import SQLAlchemy
import time
from flask import render_template , Flask
app = Flask(__name__)
app.config['TEMPLATES_AUTO_RELOAD'] = True
#app.route('/')
def index():
while True:
global time
time1 = time.time()
global time2
time2 = time.ctime(time1)
return render_template('index.html' , time3 = time2)
if __name__ == '__main__':
app.run(debug = True)
and here is my HTML code for the website:
<!DOCTYPE HTML>
<head>
</head>
<body>
<h1>{{time3}}</h1>
</body>
Can anyone help me out plz?
As I know, you can't do this only using html and python, you need to use Javascript or any other client side language. If time info will be served by python(from server) you can do it like ;
Html and JavaScript code:
<!DOCTYPE HTML>
<html>
<body>
<h>Time: </h>
<span id="time"></span>
</body>
<script type=text/javascript>
function timeClock()
{
var xhr = new XMLHttpRequest();
xhr.open("GET", "{{ url_for('time_info') }}", true);
xhr.onload = function()
{
if(this.status = 200)
{
time.innerHTML = this.response;
}
else
{
console.error(xhr);
}
};
xhr.send(null);
}
setInterval(timeClock, 1000);
</script>
</html>
Flask code:
from flask import Flask,render_template,jsonify
import time
app = Flask(__name__)
#app.route("/")
def main_page():
return render_template("index.html")
#app.route("/time_info",methods=['GET'])
def time_info():
return jsonify(time.ctime())
if __name__ == "__main__":
app.run(debug=True)
timeClock() func will send GET reqest to the server every second and python will get this request and it will send time.ctime() output to the client. Client will get this info and then it will update the html span element
I am building an App server with Python3, and the front end is done with node. js and socket. IO to connect with the back end.
A Python Flask framework is used for the back-end; similarly, a socketio and the front-end are used for connection, but the connection fails
Attempts to change the socketio version were not successful.
====================Here is the python server-side code======================
from werkzeug.exceptions import HTTPException
from flask import Flask, render_template, request, jsonify
from flask_socketio import SocketIO, emit, Namespace
from flask_cors import CORS
app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
class APINamespace(Namespace):
def on_test(self, data):
print(str(data))
emit('message', {'data': 'received ' + data['data'] + '!!!'})
socketio.on_namespace(APINamespace('/api'))
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', port=8000, debug=True)
======================Here is the HTML test code=======================
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Socket.IO Chat Example</title>
<script src="jquery-2.1.4.min.js"></script>
<script src="socket.io.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
var opts = {
'reconnection':false,
'force new connection': true,
'transports':['websocket', 'polling']
};
var socket = io.connect('http://127.0.0.1:8000/api',opts);
socket.on('message', function() {
$('#log').append('<br>connect<br>');
socket.emit('test', {'account': 'user1','name':'user1'});
});
});
</script>
</head>
<body>
<div><p id="log">这里显示信息<br></p></div>
</body>
</html>
I envision the back end actually printing out the data that comes from the front end{'account': 'user1','name':'user1'}
When the web page opens, however, the back-end console will only print this message
(3039) accepted ('127.0.0.1', 1707)127.0.0.1 - - [16/Aug/2019 14:01:10] "GET/socket.io/?EIO=3&transport=websocket HTTP/1.1" 400 122 0.000404
The front console prints an error message that the handshake failed
socket.io.js:8 WebSocket connection to 'ws://127.0.0.1:8000/socket.io/?EIO=3&transport=websocket' failed: Error during WebSocket handshake: Unexpected response code: 400
There are many tutorials available for Flask and SocketIO, I could not find any for a simple threaded approach that I understood. But I did read and followed many of them.
I'd like to show my Python application on a web page using websockets so it's kind-of real-time monitoring. This is me trying to understand how to implement this.
The code I currently have is working for except the emit part. There does not seem to be any transfer of data. I'd like to know why.
The socket.on('tingeling' ... is not being triggered.
My Python code, mostly taken from https://codeburst.io/building-your-first-chat-application-using-flask-in-7-minutes-f98de4adfa5d
from flask import Flask, render_template
from flask_socketio import SocketIO
app = Flask(__name__)
app.config['SECRET_KEY'] = ''
socketio = SocketIO(app)
thread = None
def counter():
print("counter ding")
counting = 0
while True:
counting += 1
socketio.sleep(2)
socketio.emit('tingeling', counting, namespace='')
print(f"Counter: {counting}")
#app.route('/')
def sessions():
print('route')
return render_template('index.html')
#socketio.on('my event')
def connected(data):
print('my event')
#socketio.on('connect')
def starten():
print("connect")
socketio.emit('tingeling', 'start')
global thread
if thread is None:
print('thread ding')
thread = socketio.start_background_task(target=counter())
return render_template('index.html')
if __name__ == '__main__':
socketio.run(app, debug=True)
And my HTML template:
<!DOCTYPE html>
<html lang="en">
<head>
<title>fristi</title>
</head>
<body>
<h3 style='color: #ccc;font-size: 30px;'>waiting</h3>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.min.js"></script>
<script type="text/javascript">
var socket = io.connect('http://' + document.domain + ':' + location.port);
console.log('doet iets')
socket.on( 'connect', function() {
socket.emit( 'my event', {
data: 'User Connected'
})
})
socket.on('tingeling', function(msg) {
console.log('iets komt binnen')
console.log(msg)
})
</script>
</body>
</html>
My error is on the line: thread = socketio.start_background_task(target=counter())
There I reference the function to run as a background task but I use the notation with () and that is not allowed because is runs the function and does not provide the start_background_task with a reference to this function.
I'm using web.py for python3. And gets an error.
Error:
function Render.getattr..template at 0x7fcf15a43840
main.py
import web
from web.template import render
urls = (
'/', 'Home'
)
render = web.template.render('Views/Templates/', base='MainLayout')
app = web.application(urls, globals())
#routes
class Home:
def GET(self):
return render.Home
if __name__ == '__main__':
app.run()
Views/Templates/MainLayout.html
def with (page)
<html>
<head>
<title> Title </title>
</head>
<body>
<div id='app'>
$:page
</div>
</body>
</html>
Views/Templates/Home.html
<h1> Hello World!</h1>
I have the following Python script which is using Flask-socketio
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
from time import sleep
app = Flask(__name__)
app.config['SECRET_KEY'] = 'P#ssw0rd'
socketio = SocketIO(app)
#app.route('/')
def index():
return render_template('index.html')
#socketio.on('connect')
def on_connect():
payload1 = 'Connected!!!'
payload2 = 'Doing thing 1'
payload3 = 'Doing thing 2'
emit('send_thing', payload1, broadcast=True)
sleep(2)
emit('send_thing', payload2, broadcast=True)
sleep(2)
emit('send_thing', payload3, broadcast=True)
if __name__ == '__main__':
socketio.run(app)
And here is the corresponding index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SocketIO Python</title>
</head>
<body>
<div id="my-div"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.4.5/socket.io.js"></script>
<script>
(function init() {
var socket = io()
var divElement = document.getElementById('my-div')
socket.on('send_thing', function(payload) {
var dataElement = document.createElement('inner')
dataElement.innerHTML = payload
divElement.appendChild(dataElement)
})
})()
</script>
</body>
</html>
What I am trying to achieve is that when a client connects, it first says 'Connected!!!' and then 2 seconds later a new 'inner' element appears that says 'Doing thing 1' followed by 2 seconds later a new 'inner' element appears that says 'Doing thing 2' etc.
But what is happening is that when a client connects, it sends all 3 lines at the same time (after 4 seconds which is both sleep statements). This is the first time using SocketIO so I'm sure I've done something wrong.
When you use eventlet or gevent, the time.sleep() function is blocking, it does not allow any other tasks to run.
Three ways to address this problem:
Use socketio.sleep() instead of time.sleep().
Use eventlet.sleep() or gevent.sleep().
Monkey patch the Python standard library so that time.sleep() becomes async-friendly.