Search code examples
httpgosvghttp-headersgo-http

Go HTTP will not set header for SVG


I'm generating an SVG (that will load in a separate browser window where it detects that the header is wrong), setting the content-type to "image/svg+xml", then writing the SVG, but when it is sent to the browser, it comes out as text/xml.

I'm writing the header first (which was the problem in this issue) and I'm out of ideas after moving stuff around aimlessly for a few hours.

Here is my code:

const circlesize = 2.5

// http.HandleFunc("/rendermap.svg", rendermapw)
func rendermapw(w http.ResponseWriter, r *http.Request) {
    if r.Method != "GET" {
        w.WriteHeader(405)
        return
    }
    fmt.Println("Received request " + r.URL.String())

    var mapstring string
    // already rendered
    if mapcache.valid {
        mapstring = mapcache.cache
    } else {
        // get template
        contentb, err := ioutil.ReadFile("src/maptemplate.svg")
        if err != nil {
            fmt.Println("Error with request:", r)
            fmt.Println(err)
            w.WriteHeader(500)
            return
        }
        content := strings.Split(string(contentb), "<!--template-->")

        // pull from database
        alldata := *pullall()

        mapstring = content[0] // header
        for _, e := range alldata {
            newcircle := content[1]
            //                                     string from uint64 (int64 from uint16)
            newcircle = strings.Replace(newcircle, "{ulat}", strconv.FormatInt(int64(e.Ulat), 10), 1)
            newcircle = strings.Replace(newcircle, "{ulon}", strconv.FormatInt(180-int64(e.Ulon), 10), 1)
            newcircle = strings.Replace(newcircle, "{size}", strconv.FormatFloat(circlesize, 'f', 4, 64), 1)
            mapstring += newcircle
        }
        mapstring += content[2]

        // save cache & send
        mapcache = mapcached{
            valid: true,
            cache: mapstring,
        }
    }

    // everything above this works, I'm just posting it for completion's sake

    w.WriteHeader(200)
    w.Header().Set("content-type", "image/svg+xml")

    _, err := fmt.Fprint(w, mapstring) // I also tried w.Write([]byte(mapstring))
    if err != nil {
        fmt.Println("Error with request:", r)
        fmt.Println(err)
        w.WriteHeader(500)
        return
    }
}

This is what gets sent to the browser:

Content-Type: text/xml; charset=utf-8

Here is maptemplate.svg looks like:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 360 180" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" fill="#0098ff">
    <!--template-->
    <circle cx="{ulat}" cy="{ulon}" r="{size}" fill-opacity=".5"/>
    <!--template-->
</svg>

If I remove the "<?xml version..." line, the browser gets sent text/plain.


Solution

  • I fixed it. You have to have w.Header().Set("content-type", "image/svg+xml") before w.WriteHeader(200).

    Working code:

        // ...
    
        w.Header().Set("content-type", "image/svg+xml")
        w.WriteHeader(200)
    
        _, err := fmt.Fprint(w, mapstring)
        if err != nil {
            fmt.Println("Error with request:", r)
            fmt.Println(err)
            w.WriteHeader(500)
            return
        }