Golang + CORS。 全球设置不知何故?

问题描述:

I'm trying out this small Go example https://github.com/jakecoffman/golang-rest-bootstrap, and so far so good.

I'm trying to add CORS to allow my front-end app access.

Here is my Main.go

func main() {

    var err error

    session, err = r.Connect(r.ConnectOpts{
        Address:  "localhost:28015",
        Database: "demo",
        MaxOpen:  40,
    })
    if err != nil {
        log.Fatalln(err.Error())
    }

    r := mux.NewRouter()
    users.Init(r, session)
    accounts.Init(r, session)

    r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
    })

    port := "9999" // os.Getenv("PORT")
    log.Println("Serving on", ":"+port)
    http.ListenAndServe(":"+port, context.ClearHandler(r))
}

It allows CORS at the root url, but since the other routes are handled in the controllers I just can't seem to get CORS to work there as well.

Here is part of the AccountController

func NewAccountController(r *mux.Router, s AccountService) *AccountController {
    cont := AccountController{s}
    r.Handle("/accounts", cont)
    r.Handle("/accounts/{id}", cont)

    return &cont
}

And

func (a AccountController) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    code := http.StatusMethodNotAllowed
    var data interface{}

    defer func(c int) {
        log.Println(r.URL, "-", r.Method, "-", code, r.RemoteAddr)
    }(code)

    if r.URL.Path == "/accounts" {
        switch r.Method {
        case "GET":
            code, data = a.List(w, r)
        case "POST":
            code, data = a.Add(w, r)
        default:
            return
        }
    } else {
        switch r.Method {
        case "GET":
            code, data = a.Get(w, r)
        case "PUT":
            code, data = a.Update(w, r)
        case "DELETE":
            code, data = a.Delete(w, r)
        default:
            return
        }
    }

    w.WriteHeader(code)
    w.Header().Set("Content-Type", "application/json")

    err := json.NewEncoder(w).Encode(data)
    if err != nil {
        log.Println("Failed to write data: ", err)
        code = http.StatusInternalServerError
    }
}

Any ideas or pointers would be great.

Thanks,

JB

You can make a simple middleware for that:

type CORSMiddleware struct {
    http.Handler
}

func (cm CORSMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    cm.Handler.ServeHTTP(w, r)
}

Then, you can use it like that:

var h http.Handler = CORSMiddleware{cont}
r.Handle("/accounts", h)
r.Handle("/accounts/{id}", h)