Go and Angular - POST or OPTIONs Question

4,657 views
Skip to first unread message

Daniel Lochrie

unread,
Jun 28, 2015, 3:47:17 AM6/28/15
to golan...@googlegroups.com
I built a REST application to serve resources to my Angular application and so far, so good, but I have one issue so far. I don't know if this is an Angular or Go question, but I solved the issue through some changes in Go. Here's a snippet:

(Also, I am using the Gorilla Mux package)

package app


import (
 
"appengine"
 
"github.com/gorilla/mux"
 
"net/http"
)


func init
() {
 
// Create a new router.
 r
:= mux.NewRouter()


 
// Get a reference to the People Controller.
 pc
:= PeopleController{}


 
// All of these work fine...
 r
.Handle("/people", withCORS(appHandler(pc.All))).Methods("GET")
 r
.Handle("/people", withCORS(appHandler(pc.Create))).Methods("POST")
 r
.Handle("/people/{id}", withCORS(appHandler(pc.Find))).Methods("GET")
 r
.Handle("/people/{id}", withCORS(appHandler(pc.Update))).Methods("PUT")
 r
.Handle("/people/{id}", withCORS(appHandler(pc.Delete))).Methods("DELETE")


 
// ANY POSTs from from Angular hit this route handler.
 
// WHY should I have have this handler?
 r
.Handle("/people", withCORS(appHandler(pc.Create))).Methods("OPTIONS")
}


// Simple wrapper to Allow CORS.
func withCORS
(fn appHandler) http.HandlerFunc {
 
return func(w http.ResponseWriter, r *http.Request) {
   w
.Header().Set("Access-Control-Allow-Origin", "*")
   w
.Header().Set("Access-Control-Allow-Headers", "Content-Type")
   fn
(w, r)
 
}
}

The appHandler code is pretty much verbatim from here, BTW. I omitted it from the sample above for brevity.

So I can make a POST without any modifications to /people using something like Postman, and it always works, but when I attempt an Angular POST:

http.post('http://some.url/people', payload).then(function(result) {
 
// Do something with result...
}, function() {
 
// Handle error...
});

...it ends up making an OPTIONS request, and NOT a POST request. Therefore, I had to add a route handler for "OPTIONS", (r.Handle("/people", withCORS(appHandler(pc.Create))).Methods("OPTIONS")), and it doesn't feel right. Is there something I am missing, or is there a better way to handle this (client or server-side)? Pawel Kozlowski has a great SO explanation here, but I'm still kind of confused on the Go side.

Thanks!



parais...@gmail.com

unread,
Jun 28, 2015, 5:11:34 AM6/28/15
to golan...@googlegroups.com
that's how CORS works , OPTION then whatever method is ALLOWED. 

It has nothing to do with Go. 

I don't know how gorilla mux works(never used it) but your CORS middleware needs to be able to respond to OPTION but your handlers don't have to.

I guess since gorilla mux isn't a true framework it doesn't seem like you can have global filters on top of other handlers. 
So what you need to do is wrap your entire router with the CORS handler.



Daniel Lochrie

unread,
Jul 8, 2015, 10:55:50 AM7/8/15
to golan...@googlegroups.com, parais...@gmail.com
Sorry, did not see response till now! Thank you parais...! 

That makes sense. I was able to find lots of information about CORS, but OPTION (and preflight) was new to me.

I will adjust it to wrap the router with the CORS handler as you suggested. Thanks again!

Daniel Lochrie

unread,
Jul 12, 2015, 9:04:56 PM7/12/15
to golan...@googlegroups.com, parais...@gmail.com
For anyone else that runs into this issue, I ended up wrapping the router, as @parais... mentioned, and it worked fine for me. 

(Lot's of help from these two links as well: one, two). 

It is something like:

func init() {
 
// Create a new router.
  r
:= mux.NewRouter()

  // The Default handler.
  http
.Handle("/", &WithCORS{r})
}


type
WithCORS struct {
  r
*mux.Router

}


// Simple wrapper to Allow CORS.
// See: http://stackoverflow.com/a/24818638/1058612.
func
(s *WithCORS) ServeHTTP(res http.ResponseWriter, req *http.Request) {
  if origin := req.Header.Get("Origin"); origin != "" {
    res
.Header().Set("Access-Control-Allow-Origin", origin)
    res
.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
    res
.Header().Set("Access-Control-Allow-Headers",
     
"Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
 
}

 
// Stop here for a Preflighted OPTIONS request.
 
if req.Method == "OPTIONS" {
   
return
 
}
 
// Lets Gorilla work
  s
.r.ServeHTTP(res, req)
}
Reply all
Reply to author
Forward
0 new messages