nosequeldeebee nosequeldeebee - 1 year ago 85
HTML Question

How to set different content types when using HTML/TEMPLATE package in Go

When trying to pass a value into

code I'm using the

However, I can't seem to set the
content type that is referenced in my
file. It is being served to the browser as plain text and thus formatting is ignored.

In a static
file I can use the built-in
which takes care of content types but then templating doesn't work. I can't pass in the variable. It just displays as

Is there a way to combine the
convenience of the built-in fileserver
with the template ability of

Here is my code as it stands without using
. Note, my
file is in the starting directory and the
files are in a subdirectory

package main

import (

var Message string = "test page"

func servePipe(w http.ResponseWriter, req *http.Request) {

dat, err := ioutil.ReadFile("hello/index.html")
if err != nil {
log.Fatal("couldn't read file:", err)

templ, err := template.New("Test").Parse(string(dat))

if err != nil {
log.Fatal("couldn't parse page:", err)

templ.Execute(w, Message)


func main() {

http.HandleFunc("/hello/", servePipe)
http.ListenAndServe(":8080", nil)

Here is my
file. The html page is being served without any issues. It's the separate
file that is not being served (linked in the
file) thus the formatting doesn't occur.

<!DOCTYPE html>
<title>Test Page</title>

<link rel="stylesheet" type="text/css" href="style.css"/>




Answer Source

Template.Execute() will "deliver" the content by calling the Write() method of the passed io.Writer which in your case is the http.ResponseWriter.

If you don't set the content type prior to the first call to ResponseWriter.Write() (you don't in your example), then the net/http package will attempt to detect the content type (based on the first 512 bytes written), and will set it automatically for you (along with WriteHeader(http.StatusOK) if ResponseWriter.WriteHeader() has not been called).

This is documented at http.ResponseWriter.Write():

// Write writes the data to the connection as part of an HTTP reply.
// If WriteHeader has not yet been called, Write calls
// WriteHeader(http.StatusOK) before writing the data. If the Header
// does not contain a Content-Type line, Write adds a Content-Type set
// to the result of passing the initial 512 bytes of written data to
// DetectContentType.
// ...
Write([]byte) (int, error)

So if your index.html would look like this:

    This is the body!

Then this would be properly detected as an HTML document and thus text/html content type would be automatically set. If this doesn't happen for you, that means your index.html is not recognized as an HTML document. So just make sure you make your template files valid HTML / CSS / etc. documents and content type will be inferred automatically and properly.

Also note that if it wouldn't work in some "extreme" cases, you can always "override" it by manually setting it prior to calling Template.Execute() like this:

w.Header().Set("Conent-Type", "text/html")
templ.Execute(w, Message)

Side note: don't read and parse templates inside your handlers, for details see related question: It takes too much time when using "template" package to generate a dynamic web page to client in golang

If a template served by you references other templates, they will not be magically loaded and executed. In such cases you should have a "pre-loaded" templates containing all the templates. template.ParseFiles() and template.ParseGlob() are good "tools" to load multiple template files at once.

So if your index.html references style.css, then you have to take care about serving style.css too. If it is not a template (but e.g. a static file), you may serve it using multiple options presented here: Include js file in Go template

If it is also a template, then you also have to load it and serve it by calling Template.ExecuteTemplate().

An example solution would be to load both using template.ParseFiles(), and use the path to "designate" which template you want to have served (from the client / browser side).

E.g. requesting the path /hello/index.html could serve the "index.html" template, requesting the path /hello/style.css (this will be done automatically by the browser after receiving and processing the index.html) could serve the "style.css" template. It could look like this (error checks omitted for brevity):

parts := strings.Split(req.URL.Path, "/") // Parts of the path
templName := parts[len(parts)-1]          // The last part
templ.ExecuteTemplate(w, templName, someDataForTemplate)
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download