4

I tried to ouput some data to csv file in golang beego framework, here is my code

records := make([][]string,len(devicesData))

for k,v := range devicesData{
    records[k] = []string{v.Fields.Country,v.Fields.Imei[0],v.Fields.Number[0]}
}

writer := csv.NewWriter(this.Controller.Ctx.ResponseWriter)
for _, record := range records {
    err := writer.Write(record)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
}

this.Ctx.Output.Header("Content-Type", "application/csv")
this.Ctx.Output.Header("Content-Disposition", "attachment; filename=MyVerySpecial.csv")

    writer.Flush()

However, it only shows the record data in browser, it cannot download the file. I have some loging controller and filter function before this download file controller, I do not whether it is affected. What's wrong with my code? Thanks

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
want_to_be_calm
  • 1,477
  • 3
  • 23
  • 41
  • FYI (you probably know this, I assume the above code was simplified for the question; but for other readers), if you're going to loop per record anyway you could just call `Write([]string{…})` per record rather than storing it in a `[][]string`. If however you do want to process them all first and store them in a `[][]string` then you can use [`WriteAll`](https://golang.org/pkg/encoding/csv/#Writer.WriteAll) to write all the records instead of looping again yourself. – Dave C Jun 24 '15 at 14:58

1 Answers1

3

You should always set response headers first and only after that start writing any data to the output. I know you called writer.Flush() after setting header fields, but that is no guarantee whatsoever that data will not be flushed or sent before that - which will imply default headers being sent. After this no additional headers can be sent or changed.

Also the proper mime type for CSV is text/csv not application/csv (rfc4180).

Also the headers are more like a "proposal" to the browser. That's one thing you suggest the response is a file to be saved, but from the server side you can't force the browser to really save the response to a file and not display it.

See rfc1806, rfc2183 and rfc6266 for more details about the "Content-Disposition" header field. Basically it communicates presentation information.

The Content-Disposition response header field is used to convey additional information about how to process the response payload, and also can be used to attach additional metadata, such as the filename to use when saving the response payload locally.

Community
  • 1
  • 1
icza
  • 389,944
  • 63
  • 907
  • 827