Fix: Response to preflight request doesn't pass...

Published on October 6, 2024

While working with a server using something like Go’s built-in Mux router (or any other one really), you might encounter this annoying error when you try to connect to your API running on a different port and you can’t simply throw your usual cors middleware package in for some reason:

Preflight error screenshot

It’ll be even more annoying because it is not your typical CORS error and the requests are clearly not hitting your handler functions! Don’t worry, it is an easy fix. You just need to setup a catch-all endpoints that responds to the OPTION method and returns the appropriate headers. In Robin which uses a single endpoint, it is handled this way:

// Handle CORS preflight requests mux.HandleFunc("/"+i.route, func(w http.ResponseWriter, r *http.Request) { if r.Method == "OPTIONS" { if opts.PreflightHeaders != nil { for k, v := range opts.PreflightHeaders { w.Header().Set(k, v) } return } w.Header().Set("Access-Control-Allow-Origin", strings.Join(opts.Origins, ",")) w.Header().Set("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers") w.Header().Set("Access-Control-Allow-Credentials", "true") w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS") } })

For just the Pre-Flight, you don’t necessarily need to provide all these (it depends on the browser and other things like whether you are sending credentials or not etc.), but the function this was extracted from is used for both the pre-flight and proper requests. That’s it, really, you can also just set the mode to "no-cors" in the fetch call as in:

fetch("http://foo.bar", { method: "POST", body: JSON.stringify({ d: "hello" }), mode: "no-cors", });

In case you are wondering how CorsOptions is defined, here you go:

type CorsOptions struct { // Allowed origins Origins []string // Allowed headers Headers []string // Allowed methods Methods []string // Exposed headers ExposedHeaders []string // Allow credentials AllowCredentials bool // Max age MaxAge int // Preflight headers PreflightHeaders map[string]string }

Edit this note on Github