Unable to send continuous event logs using template

81 views
Skip to first unread message

smartaq...@gmail.com

unread,
Jun 16, 2020, 3:58:16 PM6/16/20
to golang-nuts
I'm little new with golang and first time working with html templates. I need to send continuous event logs(server sent events) to the client side for which I am using flusher.

I'm facing 2 different issues here:

  1. The moment I add these 3 lines

        w.Header().Add("Content-Type", "text/event-stream")
        w.Header().Add("Cache-Control", "no-cache")
        w.Header().Add("Connection", "keep-alive")

the styles disappears from the website automatically and appears on the browser like thisenter image description here


  1. I tried to use flusher and continuously updated the body template in loop for refreshing the time after every 20 seconds using this code:

        // for {
        //  time.Sleep(20 * time.Second)
        //  welcome.Time = time.Now().Format(time.Stamp)
        //  if err := templates.ExecuteTemplate(w, "body", welcome); err != nil {
        //      http.Error(w, err.Error(), http.StatusInternalServerError)
        //  }
        //  //fmt.Fprintf(w, "data: %s\n", in.Text())
        //  flusher.Flush()
        // }

The moment I uncomment it, rather than updating the same section on the web page, template started repeating like this

Welcome Anonymous, it is Jun 16 13:09:19Jun 16 13:09:39Jun 16 13:09:59

I would be grateful if someone help me here please.

The structure of my project is:

Project
      |_ _client
                |_ _ welcome-template.css
                |_ _ background.jpeg
      |_ _ main.go 

Main.go

package main

import (
    "fmt"
    "html/template"
    "net/http"
    "time"
)

type Welcome struct {
    Name string
    Time string
}

func main() {
    htm := `{{define "layout"}}
    <!DOCTYPE html>

    <html>
       <head>
             <meta charset="UTF-8">
             <link rel="stylesheet" href="/client/welcome-template.css">

             <title>Welcome {{.Name}}</title>
       </head>
       <body>
          <div class="welcome center">Welcome {{.Name}}, it is {{template "body" .}}</div>
       </body>
    </html>
    {{end}}`
    tim := `{{define "body"}}{{.Time}}{{end}}`
    welcome := Welcome{"Anonymous", time.Now().Format(time.Stamp)}
    templates := template.Must(template.New("layout").Parse(htm))
    templates = template.Must(templates.Parse(tim))
    http.Handle("/client/", http.StripPrefix("/client/", http.FileServer(http.Dir("client"))))  

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        // flusher, ok := w.(http.Flusher)
        // if !ok {
        //  http.Error(w, "Streaming not supported", http.StatusInternalServerError)
        //  return
        // }

        w.Header().Add("Content-Type", "text/event-stream")
        w.Header().Add("Cache-Control", "no-cache")
        w.Header().Add("Connection", "keep-alive")
        if name := r.FormValue("name"); name != "" {
            welcome.Name = name
        }
        if err := templates.ExecuteTemplate(w, "layout", welcome); err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
        }
        // for {
        //  time.Sleep(20 * time.Second)
        //  welcome.Time = time.Now().Format(time.Stamp)
        //  if err := templates.ExecuteTemplate(w, "body", welcome); err != nil {
        //      http.Error(w, err.Error(), http.StatusInternalServerError)
        //  }
        //  //fmt.Fprintf(w, "data: %s\n", in.Text())
        //  flusher.Flush()
        // }

    })
    fmt.Println("Listening")
    fmt.Println(http.ListenAndServe(":8080", nil))
}

Welcome-Template.css

body  {
   min-height:100%;
   background-image: url("/client/background.jpeg"), linear-gradient(rgba(0,0,0,0.2),rgba(0,0,0,0.3));
   background-blend-mode: overlay;
   background-size:cover;
}

.welcome {
   font-family: 'Segoe UI', 'Tahoma', 'Geneva', 'Verdana', 'sans-serif';
   font-size: 3rem;
   color: aliceblue;
}

.center {
   height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
}

Brian Candler

unread,
Jun 16, 2020, 6:46:39 PM6/16/20
to golang-nuts
text/event-stream is not text/html.  text/event-stream is exactly that: a stream of (plain text) messages.  If you point a browser directly at this URL, it will render the stream as plain text.

If you want pretty rendering, what you need is a wrapper HTML page which contains some Javascript to read the event stream and insert the events into your HTML page as they arrive.

The concepts aren't Go-specific, so any page that talks about event stream (aka "server-sent events" or "eventsource") should help you.  Here are the first few I found:

smartaq...@gmail.com

unread,
Jun 19, 2020, 7:09:07 AM6/19/20
to golang-nuts
Thanks a lot Brian for the detailed information. So basically, my mistake is I was using the event/stream handler for text/html and expecting the output. Actually, I have to make a separate handler for event stream and use javascript for updating the data. 

I was thinking that templates can be used for dynamic updates. But actually they are static and once they are loaded then any update, within some section of the page(like ajax), can be done using JS through a separate handler. However, if we are ok to refresh the whole page then we can call the same template handler again. 

Thank you very very much for great help. 

Brian Candler

unread,
Jun 19, 2020, 7:46:15 AM6/19/20
to golang-nuts
You could send snippets of HTML as your "events", and have your Javascript insert or replace appropriate DOM elements with them.  That avoids full-page refreshes, which I presume is why you want to use SSE.

Or your could send unformatted data (say JSON), and have the Javascript do its own template expansion.

Depending on what you're trying to do, it might make sense to use a client-side framework like React or Vue.  There are plenty of tutorials for this: e.g.

Reply all
Reply to author
Forward
0 new messages