How to implement server push in Flask framework?
Have a look at Server-Sent Events. Server-Sent Events is a
browser API that lets you keep open a socket to your server, subscribing to a
stream of updates. For more Information read Alex MacCaw (Author of
Juggernaut) post on why he kills juggernaut and why the simpler
Server-Sent Events are in manny cases the better tool for the job than
Websockets.
The protocol is really easy. Just add the mimetype text/event-stream
to your
response. The browser will keep the connection open and listen for updates. An Event
sent from the server is a line of text starting with data:
and a following newline.
data: this is a simple message
<blank line>
If you want to exchange structured data, just dump your data as json and send the json over the wire.
An advantage is that you can use SSE in Flask without the need for an extra
Server. There is a simple chat application example on github which
uses redis as a pub/sub backend.
def event_stream():
pubsub = red.pubsub()
pubsub.subscribe('chat')
for message in pubsub.listen():
print message
yield 'data: %s\n\n' % message['data']
@app.route('/post', methods=['POST'])
def post():
message = flask.request.form['message']
user = flask.session.get('user', 'anonymous')
now = datetime.datetime.now().replace(microsecond=0).time()
red.publish('chat', u'[%s] %s: %s' % (now.isoformat(), user, message))
@app.route('/stream')
def stream():
return flask.Response(event_stream(),
mimetype="text/event-stream")
You do not need to use gunicron to run the
example app. Just make sure to use threading when running the app, because
otherwise the SSE connection will block your development server:
if __name__ == '__main__':
app.debug = True
app.run(threaded=True)
On the client side you just need a Javascript handler function which will be called when a new
message is pushed from the server.
var source = new EventSource('/stream');
source.onmessage = function (event) {
alert(event.data);
};
Server-Sent Events are supported by recent Firefox, Chrome and Safari browsers.
Internet Explorer does not yet support Server-Sent Events, but is expected to support them in
Version 10. There are two recommended Polyfills to support older browsers
- EventSource.js
- jquery.eventsource
Server-Sent Events in Flask work locally but not on production (linode)
In my experience that problem can be caused by the reverse proxy between flask and the frontend.
If you use nginx you need to set proxy_buffering
to off
in order to be able to use SSE
EDIT:
While looking at http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering I noticed that you can achieve the same result by setting the X-Accel-Buffering
header to no
in the flask response. This solution is better since it's limited to this specific response.
How can I send server-side events from Flask while accessing the request context?
You can use the @copy_current_request_context
decorator to make a copy of the request context that your event stream function can use:
from time import sleep
from flask import Flask, request, Response, copy_current_request_context
app = Flask(__name__)
@app.route('/events')
def events():
@copy_current_request_context
def _events():
while True:
# yield "Test" # Works fine
yield request.args[0]
sleep(1)
return Response(_events(), mimetype="text/event-stream")
Note that to be able to use this decorator the target function must be moved inside the view function that has the source request.
Is there a way to call a JavaScript function from flask without any client-side requests?
Without any client side request, that is going to be complicated. The information that the sqlite database changed can't just teleport from your server to the client by magic.
However, there are other solutions than polling the server at regular intervals from the client to check if information has changed: you can keep a connection from server to client open, and push notifications there.
The easiest way to implement this on the web is with "Server Sent Events".
You can check How to implement server push in Flask framework? for more information
Can flask framework send real-time data from server to client browser?
You can do so with the help of gevent
+socketio
.
- an example app using Flask with
gevent
+socketio
. - a socket.io route in Flask
- gevent-socketio
Related Topics
How to Find Numeric Columns in Pandas
Character Reading from File in Python
Coalesce Values from 2 Columns into a Single Column in a Pandas Dataframe
How to Handle Elements Inside Shadow Dom from Selenium
Django Modelform for Many-To-Many Fields
Scrolling to Element Using Webdriver
Django: Improperlyconfigured: the Secret_Key Setting Must Not Be Empty
Why Is '' > 0 True in Python 2
How to Add Multiple Annotations to a Barplot
Multiple Variables in a 'With' Statement
Binary Representation of Float in Python (Bits Not Hex)
How to Determine Whether a Year Is a Leap Year
Function Changes List Values and Not Variable Values in Python
Unicodedecodeerror When Redirecting to File
How to Get the Duration of a Video in Python
Problems with Pip Install Numpy - Runtimeerror: Broken Toolchain: Cannot Link a Simple C Program