43

所以我在 Go 中编写了这个 RESTful 后端,它将被跨站点 HTTP 请求调用,即来自另一个站点提供的内容(实际上,只是另一个端口,但同源策略生效,所以我们在这里) .

在这种情况下,用户代理将在某些情况下发送预检 OPTIONS 请求以检查实际请求是否可以安全发送。

我的问题是如何在 Go 上下文中最好地处理和充分响应这些预检请求。我构想的方式感觉不是很优雅,我想知道是否还有其他我没有想到的方法。

使用标准net/http包,我可以在处理函数 func 中检查请求方法,可能是这样的:

func AddResourceHandler(rw http.ResponseWriter, r *http.Request) {
  switch r.Method {
  case "OPTIONS":
    // handle preflight
  case "PUT":
    // respond to actual request
  }
}

我还可以使用Gorilla 的 mux包,并为每个相关的 URL 路径注册一个预检“OPTIONS”处理程序。

r := mux.NewRouter()
r.HandleFunc("/someresource/item", AddResourceHandler).Methods("PUT")
r.HandleFunc("/someresource/item", PreflightAddResourceHandler).Methods("OPTIONS")

也许对这个问题的回答很简单:是的,这些是您的基本选择。但我认为可能有一些我不知道的最佳实践。

4

5 回答 5

35

分离逻辑并重新使用您定义的 CORS 处理程序的一种简单方法是包装您的 REST 处理程序。例如,如果您使用的是 net/http 和该Handle方法,您总是可以执行以下操作:

func corsHandler(h http.Handler) http.HandlerFunc {
  return func(w http.ResponseWriter, r *http.Request) {
    if (r.Method == "OPTIONS") {
      //handle preflight in here
    } else {
      h.ServeHTTP(w,r)
    }
  }
}

你可以这样包装:

http.Handle("/endpoint/", corsHandler(restHandler))
于 2014-04-09T20:54:42.283 回答
9

我个人觉得为将获得OPTIONS请求的每个路径添加预检路由很乏味,因此我只是将我的处理程序添加到OPTIONS请求多路复用器(在本例中为 Gorilla)处理的任何方法中,如下所示:

router.Methods("OPTIONS").HandlerFunc(
    func(w http.ResponseWriter, r *http.Request){
    myHttpLib.OptionsForBrowserPreflight(w, r)
})

但是请注意,这应该在映射其他路由之前进行,因为例如,如果您有一个类似的路径"/foo"并且您首先注册该路径而没有为该路由指定任何方法,那么对“/foo”的 OPTIONS 请求将运行而不是您的 pre -flight 代码,因为它是第一个匹配项。

通过这种方式,您可以:(1) 为所有预飞行只有一个路由注册,(2) 有一个处理程序来重用代码并在一个地方为 OPTIONS 请求应用逻辑/规则。

于 2016-09-13T20:49:11.417 回答
7

这是一个对我有用的片段:

addCorsHeader(res)
if req.Method == "OPTIONS" {
    res.WriteHeader(http.StatusOK)
    return
} else {
    h.APIHandler.ServeHTTP(res, req)
}


func addCorsHeader(res http.ResponseWriter) {
    headers := res.Header()
    headers.Add("Access-Control-Allow-Origin", "*")
    headers.Add("Vary", "Origin")
    headers.Add("Vary", "Access-Control-Request-Method")
    headers.Add("Vary", "Access-Control-Request-Headers")
    headers.Add("Access-Control-Allow-Headers", "Content-Type, Origin, Accept, token")
    headers.Add("Access-Control-Allow-Methods", "GET, POST,OPTIONS")
}
于 2018-03-10T19:47:22.940 回答
6

gorilla/handlers也有一个不错的 CORS 处理程序:cors.go

示例用法:

import (
    "net/http"

    "github.com/gorilla/handlers"
    "github.com/gorilla/mux"
)

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/users", UserEndpoint)
    r.HandleFunc("/projects", ProjectEndpoint)

    // Apply the CORS middleware to our top-level router, with the defaults.
    http.ListenAndServe(":8000", handlers.CORS()(r))
}
于 2016-11-07T14:33:55.710 回答
1

好吧,我的 Vue.js 应用程序没有任何效果,所以我这样做了。

cors := cors.New(cors.Options{
        AllowedOrigins:   []string{"*"}, //viper.GetString("ORIGIN_ALLOWED")
        AllowedHeaders:   []string{"Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token", "Authorization"},
        AllowedMethods:   []string{"GET", "PATCH", "POST", "PUT", "OPTIONS", "DELETE"},
        Debug:            true,
        AllowCredentials: true,
    })

cors.Handler(corsMiddle())
func corsMiddle() http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {
        if request.Method == "OPTIONS" {
            w.WriteHeader(http.StatusOK)
        }
    })
}
于 2019-10-19T13:10:10.223 回答