Hallo,
hier meine Scripts, die SSE ganz gut demonstrieren. (s.u.)
Die Scripts laufen auf einem Raspberry mit Apache2.
'sse_py.html' startet 'sse.py' und öffnet die Verbindung mit:
const sse = new EventSource("/cgi-bin/sse.py");
sse.py muss mit: print("Content-Type: text/event-stream") + 2x LF antworten.
Das Ergebnis der Verbindung kann in sse.onopen oder sse.onerror abgefragt werden.
Wenn alles ok,
können in sse.py, in einer Endlosschleife, die 'events' ausgegeben werden.
Ein 'event' wird immer mit Key: 'event: <wert>' und dem Key: 'data: <wert>' + 2x LF übergeben.
Ein event-wert wird im Browser in der entspr. 'addEventListener'-Funktion verarbeitet,
oder landet in der onmessage-Funktion.
z.B. "event: myFunc" --> sse.addEventListener("myFunc",....)
Mit data-wert wird ein beliebiger String übergeben. (2x LF nicht vergessen)
Sollte die SSE-Verbindung unterbrochen werden, wird sie vom Browser autom. wieder geöffnet.
Wenn nach ca. 5 Minuten keine events mehr empfangen werden, beendet der Browser von
sich aus die Verbindung, versucht aber direkt wieder eine Neue zu eröffnen.
Will man das verhindern, kann man z.B. timergesteuert jede Minute ein dummy-event abschicken.
print("event: message");
print("data: Ping \n");
Hier mal meine 'event: daten' Verarbeitung:
vom Server wird mit 'data:' eine Protokollzeile als JSON-String gesendet.
im Javascript:
const arr1 = [ "DATE", "TIME", "espName", "mcc", "msg" ];
const arr2 = [ "Datum", "Uhrzeit", "Espname", "MAC-Adr", "Info" ];
sse.addEventListener("daten", (e) => {
console.log("daten: " + e.data);
let obj = JSON.parse(e.data); // = array mit objecten
var row = tbo.insertRow(-1);
for (let i=0; i < arr1.length; i++) {
var cell = row.insertCell(-1);
cell.setAttribute("data-title", arr2
);
cell.innerHTML = obj[arr1];
}
});
'tbo' ist die <tbody>-ID. Hier entstehen die Tabellen-Zeilen.
Mit 'arr1' gebe ich an, welche JSON-Daten ich sehen will.
Mit 'arr2' gebe ich an, wie die Tabelle im 'Handy-Modus' aussehen soll.
Wenn die Protokolldatei angezeigt ist, bleibt das Programm in einer Endlosschleife und wartet auf einen neuen Satz.
Sobald einer eingetragen wird, wird er per 'event' zum Browser gesendet und direkt angezeigt.
Code: Alles auswählen
<!DOCTYPE HTML>
<!--
P:\www\html\sse_py.html
-->
<html>
<head>
<meta charset="UTF-8">
<title>Server-sent events demo</title>
</head>
<body>
<div id = "sse">
Server-sent events demo <br>
(Ausgabe in Browser-Konsole)
</div>
<br>
<button>Close the connection</button>
<br>
<script type = "text/javascript">
//---------------------------------------------------------------------
function getDateTime() {
var currentdate = new Date();
var dateTime = currentdate.getFullYear() + "." +
("00" + (currentdate.getMonth() + 1)).slice(-2) + "." +
("00" + currentdate.getDate()).slice(-2) + " / " +
("00" + currentdate.getHours()).slice(-2) + ":" +
("00" + currentdate.getMinutes()).slice(-2) + ":" +
("00" + currentdate.getSeconds()).slice(-2);
return dateTime;
};
//---------------------------------------------------------------------
// if (!!window.EventSource) {
const button = document.querySelector('button');
const sse = new EventSource("/cgi-bin/sse.py");
console.log(sse.withCredentials);
console.log(sse.readyState);
console.log(sse.url);
sse.onopen = function() {
console.log("Connection to server opened.");
console.log(getDateTime());
};
sse.onmessage = function(e) {
console.log("onmessage: " + e.data);
};
sse.onerror = function() {
console.log("EventSource failed.");
console.log(getDateTime());
};
sse.addEventListener("myFunc", (e) => {
console.log("myFunc: " + e.data);
// console.log(e.origin); = http://<IP>
});
sse.addEventListener("ende", (e) => {
console.log("ENDE: " + e.data);
sse.close();
});
button.onclick = function() {
console.log('Connection closed');
sse.close();
};
</script>
</body>
</html>
##################################################################
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# P:\www\cgi-bin\sse.py
import time
from datetime import datetime
print("Content-Type: text/event-stream")
print("Cache-Control: no-cache\n") # 2x LF
count = 0
while True:
count += 1
if count > 5:
# print("event: ende")
# print(f"data: *** sse-Ende ***\n",flush=True)
break
datum = datetime.now().strftime("%Y.%m.%d")
uhrzeit = datetime.now().strftime("%H:%M:%S")
print("event: myFunc")
print(f"data: ---{uhrzeit}--- count: {count}\n",flush=True)
# abschluss mit 2x LF, sonst wird das nicht als eigener event
# gesehen und mit dem naechsten verknuepft
print("event: message")
print(f"data: +++{uhrzeit}+++\n",flush=True)
# abschluss mit 2x LF
time.sleep(5);
while True:
pass
-------------------------------------------------------------------------------------------
Consol-Ausgabe
--------------------------
myFunc: ---17:07:41--- count: 5 --> und anschl. in Endlosschleife
onmessage: +++17:07:41+++
---> nach ca. 5 Minuten ohne 'event' beendet der Browser die Verbindung
EventSource failed.
2024.02.28 / 17:12:47
---> und eröffnet eine neue Verbindung
Connection to server opened.
2024.02.28 / 17:12:52
myFunc: ---17:12:52--- count: 1
...
Ich hoffe, ich konnte etwas zum Thema: SSE beitragen.
Gruß erima