itsjokaful
Goto Top

Server Sent Events in Golang - Browser get event stream funktioniert nur bei localhost

Servus,

ich möchte "Server Sent Events" mit Golang realisieren. Ich benutze dafür die hier beschriebene Bibliothek: https://thoughtbot.com/blog/writing-a-server-sent-events-server-in-go

Es hat auch funktioniert, aber nur mit localhost. Wenn ich meinen Hostnamen in der Adresszeile meines Browsers eingebe, funktioniert die Übertragung nicht. Es funktioniert auch nicht, wenn ich die Website auf einem anderen Client aufrufe.

Wenn ich ein SSE an den Client sende und die Serveranwendung beende, gehen alle Ereignisse sofort bei der Browseranwendung ein. Wenn ich cURL benutze, funktioniert es:

curl -v myhost:8081/updates
*   Trying ....
* TCP_NODELAY set
* Connected to myhost (...) port 8081 (#0)
> GET /updates HTTP/1.1
> Host: myhost:8081
> User-Agent: curl/7.50.3
> Accept: */*
>
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Cache-Control: no-cache
< Connection: keep-alive
< Content-Type: text/event-stream
< Date: Fri, 29 Nov 2019 17:07:27 GMT
< Transfer-Encoding: chunked
<
data: {"X":127,"Y":227,"Zeitpunkt":"29.11.2019 18:07:27"}  

data: {"X":128,"Y":228,"Zeitpunkt":"29.11.2019 18:07:28"}  

data: {"X":128,"Y":228,"Zeitpunkt":"29.11.2019 18:07:29"}  


Woran könnte das liegen? Ich benutze die neueste Golang-Bibliothek

Hier ist mein Javascript-Code:

  <script>
    if(typeof(EventSource) !== "undefined") {  
        var source = new EventSource("updates");  
        source.onmessage = function(event) {
            var pmstat = jQuery.parseJSON(event.data);
            $('#bestandX').html(pmstat.X);  
            $('#bestandY').html(pmstat.Y);  
            $('#aktualisiertAm').html(pmstat.Zeitpunkt);  
        };

    } else {
        $('body').html('<h1 style="color: red">Browser unterstützt keine Server-sent events.</h1>')  
    }
  </script>

Und hier ist der Golang-Code, den ich aus der Bibliothek verwende:
// Implement the http.Handler interface.
// This allows us to wrap HTTP handlers (see auth_handler.go)
// http://golang.org/pkg/net/http/#Handler
func (broker *Broker) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
    // Make sure that the writer supports flushing.
    //
    flusher, ok := rw.(http.Flusher)

    if !ok {
        http.Error(rw, "Streaming unsupported!", http.StatusInternalServerError)  
        return
    }

    // Set the headers related to event streaming.
    rw.Header().Set("Content-Type", "text/event-stream")  
    rw.Header().Set("Cache-Control", "no-cache")  
    rw.Header().Set("Connection", "keep-alive")  
    rw.Header().Set("Access-Control-Allow-Origin", "*")  

    // Each connection registers its own message channel with the Broker's connections registry  
    messageChan := make(MessageChan)

    // Signal the broker that we have a new connection
    broker.newClients <- messageChan

    // Remove this client from the map of connected clients
    // when this handler exits.
    defer func() {
        fmt.Println("HERE.")  
        broker.closingClients <- messageChan
    }()

    // "raw" query string option  
    // If provided, send raw JSON lines instead of SSE-compliant strings.
    req.ParseForm()
    raw := len(req.Form["raw"]) > 0  

    // Listen to connection close and un-register messageChan
    notify := rw.(http.CloseNotifier).CloseNotify()

    go func() {
        <-notify
        broker.closingClients <- messageChan
    }()

    // block waiting or messages broadcast on this connection's messageChan  
    for {
        // Write to the ResponseWriter
        if raw {
            // Raw JSON events, one per line
            fmt.Fprintf(rw, "%s\n", <-messageChan)  
        } else {
            // Server Sent Events compatible
            fmt.Fprintf(rw, "data: %s\n\n", <-messageChan)  
        }
        // Flush the data inmediatly instead of buffering it for later.
        flusher.Flush()

    }
}

Die Bibliothek habe ich auch schon ausprobiert, das gleiche passiert aber auch hier: https://github.com/alexandrevicenzi/go-sse

Dann habe ich versucht, die Verbindung nach jeder Nachricht zu trennen und dem Browser den Befehl zu geben, die Verbindung sofort wiederherzustellen.
Hier sind die zwei Zeilen, die ich im Code hinzugefügt habe:
...
    go func() {
        <-notify
        broker.closingClients <- messageChan
    }()

    // block waiting or messages broadcast on this connection's messageChan 
    for {
        // Write to the ResponseWriter
        if raw {
            // Raw JSON events, one per line
            fmt.Fprintf(rw, "%s\n", <-messageChan)  
        } else {
            // Server Sent Events compatible
            fmt.Fprintf(rw, "retry: %d\n", 0) //<--- I added this  
            fmt.Fprintf(rw, "data: %s\n\n", <-messageChan)  
        }
        // Flush the data inmediatly instead of buffering it for later.
        flusher.Flush()
        break //<--- I added this
    }
}

So funktioniert es, aber das ist nur ein Workaround für mich. Problem ist, das zwischen der Zeit, nach der die Verbindung beendet und wieder eine neue Verbindung aufgebaut wurde, keine Aktualisierung stattfindet. Hat jemand eine bessere Lösung, wie es funktioniert, während die Verbindung bestehen bleibt?

Content-Key: 521735

Url: https://administrator.de/contentid/521735

Printed on: June 21, 2024 at 20:06 o'clock

Member: ItsJokaful
ItsJokaful Dec 06, 2019 at 07:42:27 (UTC)
Goto Top
Gelöst...
Lag am internen Anti-Viren Programm. Sophos