【问题标题】:Making golang Gorilla CORS handler work使 golang Gorilla CORS 处理程序工作
【发布时间】:2017-04-20 12:50:00
【问题描述】:

我在这里有相当简单的设置,如下面的代码所述。但我无法让CORS 工作。我不断收到此错误:

XMLHttpRequest 无法加载 http://localhost:3000/signup。回应 预检请求未通过访问控制检查:否 'Access- 请求的资源上存在 Control-Allow-Origin 标头。 因此,Origin 'http://localhost:8000' 不允许访问。这 响应的 HTTP 状态代码为 403。

我确定我在这里遗漏了一些简单的东西。

这是我的代码:

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

【问题讨论】:

标签: go cors gorilla servemux


【解决方案1】:

请阅读 Markus 建议的链接,以及触发 CORS 飞行前请求的原因。

飞行前请求:您可能有 JSON 等内容类型,或触发飞行前请求的其他自定义标头,您的服务器可能无法处理这些请求。如果您在前端使用常见的 AJAX,请尝试添加这个:https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requested-With

Gorilla 的 handlers.CORS() 将设置合理的默认值,让 CORS 的基础知识为您工作;但是,您可以(也许应该)以更实用的方式进行控制。

这里有一些启动代码:

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

【讨论】:

  • 只是一些记账:Safari 喜欢在执行“非标准”操作(例如 PUT)时发送 Content-Type 请求标头,因此您需要让您的 CORS 标头允许Content-Type 也是。 headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type"})related reference in Gorilla CORS package
【解决方案2】:

您可以在此处获取更多详细信息:Why doesn’t Postman get a "No 'Access-Control-Allow-Origin' header is present on the requested resource" error when my JavaScript code does? 关于此问题。

也试试这个处理程序:Go Cors Handler 应该可以解决您的问题。我发现这更干净,更容易解决问题。

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

【讨论】:

  • 谢谢,使用 github.com/rs/cors 最简单且有效
  • 这更精简,真的很棒......非常感谢老兄! @from_Tanzania
  • 就是这么简单。谢谢男人
【解决方案3】:

您应该创建一个CORSOption 对象。例如要允许任何来源,请使用以下代码:

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

然后你将这个对象传递给你的handle.CORS 函数:

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

为了测试它,你可以使用 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

当它起作用时,您应该会看到这些标题:

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

最终代码在这里:https://play.golang.org/p/AOrlJsWhvf

更多信息:

【讨论】:

    【解决方案4】:
    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))
    }
    

    【讨论】:

    【解决方案5】:

    声明mux对象后,将accessControlMiddleware作为中间件添加到声明的对象中。

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

    【讨论】:

    • 我的问题是没有处理“OPTIONS”的实际请求,所以像你所做的那样在中间件中粘贴返回响应是有道理的。
    【解决方案6】:

    基于 jeremiah.trein 的回答。

    CORS 过滤器设置在服务器端。请求可能与 Postman 一起使用,而在浏览器中失败,因为 Postman 不会发送预检请求,而浏览器会发送。

    设置 CORS 过滤器将允许您配置后端应接受的来源、方法和标头。

    此外,如果您的浏览器发出包含 json 有效负载的 POST 或 PUT 请求(这很合理),您需要将'Content-Type' 添加到允许的标头中。

    最后handlers.CORS()(router) 不仅适用于http.ListenAndServe 函数,还适用于http.Handle()

    sn-p 的代码不妨如下:

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

    值得一提的是,我已经在 Google Cloud Platform Standard AppEngine 中成功使用了这个 sn-p 代码(我相信它也可以在 Flex AppEngine 中使用)。

    【讨论】:

      【解决方案7】:

      我意识到这是一个老问题,但我还是花了 30 分钟才解决这个问题。

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

      注意事项:

      • AllowedMethods 不需要显式包含 OPTIONS,这是 CORS 处理程序的一部分
      • AllowedHeaders 需要明确提及,* 不是有效的通配符。当请求 application/json 之类的内容时,典型的 ajax 库会发送 Content-Type,所以也要添加它。
      • * 是 AllowedOrigin 的默认值

      【讨论】:

      【解决方案8】:

      上述包github.com/rs/cors提供了一个构造函数

      AllowAll() *Cors
      

      那个

      ...创建一个具有许可配置的新 Cors 处理程序,允许所有 起源于具有任何标头和凭据的所有标准方法。

      【讨论】:

        猜你喜欢
        • 2016-05-06
        • 2015-03-20
        • 2016-09-23
        • 1970-01-01
        • 2016-04-10
        • 2023-02-21
        • 2020-08-26
        • 1970-01-01
        相关资源
        最近更新 更多