A file proxy in Go on App Engine
When you want to proxy some files in your Go project running on Google App Engine, the standard Go proxy does not work. Instead, App Engine uses a custom implementation for proxies, called urlfetch
.
It looks like this to proxy an image (or any other file):
package main
import (
"appengine"
"appengine/urlfetch"
"bytes"
"github.com/gorilla/mux"
"net/http"
)
func main() {
router := mux.NewRouter()
router.HandleFunc("/", RootHandler)
http.Handle("/", router)
http.ListenAndServe(":3000", nil)
}
func RootHandler(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
client := urlfetch.Client(c)
response, err := client.Get("https://roka.cloudant.com/roka-photography/strawberries/full.jpg")
if err != nil {
c.Errorf("downloadProxy: %v", err)
return
}
// Convert from to io.ReadCloser a buffer.
var buf bytes.Buffer
buf.ReadFrom(response.Body)
// Write the buffer out to the client
w.Write(buf.Bytes())
}
First, the image is fetched via the App Engine specific urlfetch.Client
. The response.Body
then get’s converted to a buffer and finally written out to the client.
The problem I ran into was a corrupt image file at first. As I found out, it is not wise to read from the buffer more than once. I was logging out the response.Header
, too, at first but that somehow prepended it to image file which ended up incorrect.
After some time digging around it sounds so easy and straight forward, that it’s hard to believe I’ve spent so much time looking for a solution. But it’s always like this.