Python server push message to client actively via server sent event (SSE) event stream, event source listen onmessage and onerror

//app.py
from flask import Flask, render_template, Response
import random
import time
from datetime import datetime
import threading
import json

app = Flask(__name__)
messages = []
obj_lock = threading.Lock()

def generate_random_number():
    global messages
    while True:
        num = random.randint(80, 101)
        if num > 90:
            current_time = datetime.now().strftime('%Y%m%d%H%M%S%f')

            with obj_lock:
                if len(messages)>=10:
                    messages.clear()
                messages.append({
                    "current_time": current_time,
                    "number": num
                })
                print(f'In generate_random_number(), current_time:{current_time}, number:{num}, len:{len(messages)}')
        time.sleep(1)    

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

@app.route('/stream')
def stream():
    def event_stream():
        global messages
        try:
            last_idx = 0
            with app.app_context():
                while True:
                    with obj_lock:
                        if len(messages)>=10:
                            messages.clear()
                            last_idx=0
                            continue

                        if len(messages) > last_idx:
                            for msg in messages[last_idx:]:
                                msg_json = json.dumps(msg, ensure_ascii=False)
                                msg_str = f"data: {msg_json}\n\n"
                                print(f'In event_stream(), {datetime.now()}, {msg_str.strip()}')
                                yield msg_str
                            last_idx = len(messages)

                time.sleep(0.1)
        except Exception as ex:
            print(f'{datetime.now()},{str(ex)}')
    response = Response(event_stream(), mimetype="text/event-stream")
    response.headers['Cache-Control'] = 'no-cache'
    response.headers['X-Accel-Buffering'] = 'no'
    return response

if __name__ == '__main__':
    threading.Thread(target=generate_random_number, daemon=True).start()
    app.run(debug=True, threaded=True)

//Templates/index.html
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <title>Flask Push Actively</title> 
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

    <style>
        table {
            width: 600px;
            border-collapse: collapse;
            margin: 20px 0;
        }

        th,
        td {
            border: 1px solid #ccc;
            padding: 8px 12px;
            text-align: center;
        }

        th {
            background-color: #f5f5f5;
        }

        .container {
            margin: 20px;
        }
    </style>
</head>

<body>
    <div class="container">
        <h2>Flask push random number which is greater than 90(80-100)</h2>
        <table id="dataTable">
            <thead>
                <tr>
                    <th>Id</th>
                    <th>GenerateTime</th>
                    <th>RandomNumber</th>
                </tr>
            </thead>
            <tbody>
            </tbody>
        </table>
    </div>

    <script>
        function get_time_now() {
            const now = new Date();
            const year = now.getFullYear();
            const month = String(now.getMonth() + 1).padStart(2, '0');
            const day = String(now.getDate()).padStart(2, '0');
            const hour = String(now.getHours()).padStart(2, '0');
            const minute = String(now.getMinutes()).padStart(2, '0');
            const second = String(now.getSeconds()).padStart(2, '0');
            const ms = String(now.getMilliseconds()).padStart(3, '0').slice(-2);
            return `${year}${month}${day}${hour}${minute}${second}${ms}`;
        }

        $(document).ready(function () {
            let serialNumber = 1;
            const eventSource = new EventSource("/stream");

            eventSource.onmessage = function (event) {
                const data = JSON.parse(event.data);
                console.log(get_time_now(),data.current_time,data.number)
                const newRow = `
                    <tr>
                        <td>${serialNumber}</td>
                        <td>${data.current_time}</td>
                        <td>${data.number}</td>
                    </tr>
                `;
                $("#dataTable tbody").append(newRow);
                serialNumber++;
            };

            eventSource.onerror = function (error) {
                console.error("SSE connection error", error);
                eventSource.close();
                setTimeout(() => {
                    window.location.reload();
                }, 3000);
            };
        });

    </script>
</body>

</html>

 

 

 

 

image

 

 

 

 

 

 

image

 

 

 

image

 

posted @ 2026-03-09 20:32  FredGrit  阅读(12)  评论(0)    收藏  举报