【问题标题】:How to handle preflight CORS requests on a Go server如何在 Go 服务器上处理预检 CORS 请求
【发布时间】:2014-05-23 05:12:24
【问题描述】:

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

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

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

使用标准的net/http包,我可以在handler func中查看请求方法,大概是这样的:

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

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

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

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

【问题讨论】:

  • 是的,这些是您的基本选择 :) 了解您还期待什么会有所帮助 - 例如,是否有其他语言可以完全不同地处理它?
  • 啊!添加一个预检处理程序——非常感谢你发布这个!正是我需要的。

标签: go cors preflight


【解决方案1】:

分离逻辑并重用您定义的 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))

【讨论】:

  • 谢谢,你让我走上正轨!我已经有一个拦截corsHandler,它只是在委派给“真实”处理程序之前对默认的 CORS 标头产生影响。通过基于请求方法进行条件委托,我得到了一个有点 DRY:er 的解决方案。
  • 参数不应该是h http.HandlerFunc,而不是h http.Handler吗?
  • 在尝试使用 Gorilla CORS 功能和其他一些选项但没有成功后,我发现这个答案非常有用。在作者建议“//handle preflight”的地方,我使用了这些特定的调用:log.Print("preflight detected: ", r.Header)w.Header().Add("Connection", "keep-alive") w.Header().Add("Access-Control-Allow-Origin", "http://localhost:3000") w.Header().Add("Access-Control-Allow-Methods", "POST, OPTIONS, GET, DELETE, PUT") w.Header().Add("Access-Control-Allow-Headers", "content-type") w.Header().Add("Access-Control-Max-Age", "86400")
  • 飞行前处理的典型逻辑是什么?浏览器希望在飞行前响应中看到什么?
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

    这是一个对我有用的 sn-p:

    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")
    }
    

    【讨论】:

    • 您永远不需要允许 Origin 标头。
    【解决方案4】:

    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))
    }
    

    【讨论】:

      【解决方案5】:

      嗯,我的 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)
              }
          })
      }
      

      【讨论】:

      • 如何导入cors
      • @PrinceHamza 使用这个"github.com/rs/cors"
      • AllowedOrigins: []string{"*"}AllowCredentials: true 不兼容。
      猜你喜欢
      • 2018-11-12
      • 2014-10-31
      • 2016-02-17
      • 2013-11-25
      • 2014-08-16
      • 1970-01-01
      • 2014-03-14
      • 2021-05-11
      • 2019-08-29
      相关资源
      最近更新 更多