Moon
Moon

Reputation: 35265

Making golang Gorilla CORS handler work

I have fairly simple setup here as described in the code below. But I am not able to get the CORS to work. I keep getting this error:

XMLHttpRequest cannot load http://localhost:3000/signup. Response to preflight request doesn't pass access control check: No 'Access- Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. The response had HTTP status code 403.

I am sure I am missing something simple here.

Here is the code I have:

package main

import (
    "log"
    "net/http"

    "github.com/gorilla/handlers"
    "github.com/gorilla/mux"
    "myApp/src/controllers"
)

func main() {
    ac := new(controllers.AccountController)

    router := mux.NewRouter()
    router.HandleFunc("/signup", ac.SignUp).Methods("POST")
    router.HandleFunc("/signin", ac.SignIn).Methods("POST")

    log.Fatal(http.ListenAndServe(":3000", handlers.CORS()(router)))
}

Upvotes: 51

Views: 72155

Answers (8)

Yurkol
Yurkol

Reputation: 1482

The aformentioned package github.com/rs/cors provides a constructor

AllowAll() *Cors

that

...create a new Cors handler with permissive configuration allowing all origins with all standard methods with any header and credentials.

Upvotes: 0

user5906464
user5906464

Reputation:

You can get more details here: Why doesn’t Postman get a "No 'Access-Control-Allow-Origin' header is present on the requested resource" error when my JavaScript code does? about this issue.

Also try this handler: Go Cors Handler which should solve your issue. I find this much cleaner and easy to resolve the issue.

package main

import (
    "log"
    "net/http"
    "github.com/rs/cors"
    "github.com/gorilla/handlers"
    "github.com/gorilla/mux"
    "myApp/src/controllers"
)

func main() {
    ac := new(controllers.AccountController)

    router := mux.NewRouter()
    router.HandleFunc("/signup", ac.SignUp).Methods("POST")
    router.HandleFunc("/signin", ac.SignIn).Methods("POST")

    c := cors.New(cors.Options{
        AllowedOrigins: []string{"http://localhost:8000"},
        AllowCredentials: true,
    })

    handler := c.Handler(router)
    log.Fatal(http.ListenAndServe(":3000", handler)
}

Upvotes: 40

andig
andig

Reputation: 13868

I realize this is an old issue but nonetheless it took me 30min to get this right.

handler = handlers.CORS(
    // handlers.AllowedMethods([]string{"GET", "POST", "PUT"}),
    handlers.AllowedHeaders([]string{"Accept", "Accept-Language", "Content-Type", "Content-Language", "Origin"}),
    // handlers.AllowedOrigins([]string{"*"}),
)(handler)

Things to note:

  • AllowedMethods does NOT need to explicitly include OPTIONS, this is part of the CORS handler
  • AllowedHeaders need to be explicitly mentioned, * is not a valid wildcard. Typical ajax libraries will send Content-Type when requesting something like application/json, so add that as well.
  • * is the default for AllowedOrigin

Upvotes: 8

avi.elkharrat
avi.elkharrat

Reputation: 6780

Base on jeremiah.trein's answer.

CORS filters are set on server side. Request may work with Postman and fail with a browser because Postman doesn't send preflight request whereas a browser does.

Setting the CORS filters will allow you to configure the origins, methods and headers that the backend shall accept.

In addition, if your browser emits POST or PUT requests that contain a json payload (which is quite reasonnable), you'll need to add 'Content-Type' to the allowed headers.

Finally the handlers.CORS()(router) does not only work with the http.ListenAndServe function but also with http.Handle().

The snippet of code might as well look like:

router := mux.NewRouter()

// do all your routes declaration

headersOK := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type"})
originsOK := handlers.AllowedOrigins([]string{"*"})
methodsOK := handlers.AllowedMethods([]string{"GET", "POST", "OPTIONS", "DELETE", "PUT"})

http.Handle("/", handlers.CombinedLoggingHandler(os.Stderr, handlers.CORS(headersOK, originsOK, methodsOK)(router)))

It is worth mentionning that i have successfuly used this snippet of code in a Google Cloud Platform Standard AppEngine (and I believe it would work in a Flex AppEngine as well).

Upvotes: 4

TiGo
TiGo

Reputation: 617

After declaring the mux object, add the accessControlMiddleware as a middleware to the declared object.

func main(){
  ac := new(controllers.AccountController)

    router := mux.NewRouter()
    router.Use(accessControlMiddleware)
    router.HandleFunc("/signup", ac.SignUp).Methods("POST")
    router.HandleFunc("/signin", ac.SignIn).Methods("POST")
    http.ListenAndServe(":3000", corsOpts.Handler(router))
}

// access control and  CORS middleware
func accessControlMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            w.Header().Set("Access-Control-Allow-Origin", "*")
            w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS,PUT")
            w.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type")

                if r.Method == "OPTIONS" {
                    return
                }

                next.ServeHTTP(w, r)
            })
        }

Upvotes: 7

jeremiah.trein
jeremiah.trein

Reputation: 806

Please read the link Markus suggested, and also about what triggers CORS pre-flight requests.

Pre-flight requests: You may have a content type like JSON, or some other custom header that's triggering a pre-flight request, which your server may not be handling. Try adding this one, if you're using the ever-common AJAX in your front-end: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requested-With

Gorilla's handlers.CORS() will set sane defaults to get the basics of CORS working for you; however, you can (and maybe should) take control in a more functional manner.

Here's some starter code:

// Where ORIGIN_ALLOWED is like `scheme://dns[:port]`, or `*` (insecure)
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With"})
originsOk := handlers.AllowedOrigins([]string{os.Getenv("ORIGIN_ALLOWED")})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})

// start server listen
// with error handling
log.Fatal(http.ListenAndServe(":" + os.Getenv("PORT"), handlers.CORS(originsOk, headersOk, methodsOk)(router)))

Upvotes: 68

muthukumar selvaraj
muthukumar selvaraj

Reputation: 1073

package main

import (
    "log"
    "net/http"

    "github.com/gorilla/handlers"
    "github.com/gorilla/mux"
    "myApp/src/controllers"
       "github.com/rs/cors"
)

func main() {

     ac := new(controllers.AccountController)

    router := mux.NewRouter()
    router.HandleFunc("/signup", ac.SignUp).Methods("POST")
    router.HandleFunc("/signin", ac.SignIn).Methods("POST")
//cors optionsGoes Below
corsOpts := cors.New(cors.Options{
    AllowedOrigins: []string{"http://localhost:8100"}, //you service is available and allowed for this base url 
    AllowedMethods: []string{
        http.MethodGet,//http methods for your app
        http.MethodPost,
        http.MethodPut,
        http.MethodPatch,
        http.MethodDelete,
        http.MethodOptions,
        http.MethodHead,
    },

    AllowedHeaders: []string{
        "*",//or you can your header key values which you are using in your application

    },
})

    http.ListenAndServe(":3000", corsOpts.Handler(router))
}

Upvotes: 4

Aminadav Glickshtein
Aminadav Glickshtein

Reputation: 24590

You should create a CORSOption object. For example to allow any origin, Use this code:

corsObj:=handlers.AllowedOrigins([]string{"*"})

Then you pass this object to your handle.CORS function:

log.Fatal(http.ListenAndServe(":3000", handlers.CORS(corsObj)(router)))

For testing it you can use CURL:

curl -H "Origin: http://example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: X-Requested-With" \
-X OPTIONS --verbose http://127.0.0.1:3000

When it works you should see those headers:

> Accept: */*
> Origin: http://example.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: X-Requested-With

Final code is here: https://play.golang.org/p/AOrlJsWhvf

More info:

Upvotes: 21

Related Questions