使golang Gorilla CORS处理程序正常工作

huangapple go评论79阅读模式
英文:

Making golang Gorilla CORS handler work

问题

我在下面的代码中描述了一个相当简单的设置。但是我无法使CORS工作。我一直收到以下错误信息:

> XMLHttpRequest无法加载http://localhost:3000/signup。对预检请求的响应未通过访问控制检查:请求的资源上没有'Access-Control-Allow-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)))
}
英文:

I have fairly simple setup here as described in the code below. But I am not able to get the CORS to work. I keep getting this error:

> XMLHttpRequest cannot load http://localhost:3000/signup. Response to
> preflight request doesn't pass access control check: No 'Access-
> Control-Allow-Origin' header is present on the requested resource.
> Origin 'http://localhost:8000' is therefore not allowed access. The
> response had HTTP status code 403.

I am sure I am missing something simple here.

Here is the code I have:

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

答案1

得分: 65

请阅读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)))
英文:

Please read the link Markus suggested, and also about what triggers CORS pre-flight requests.

Pre-flight requests: You may have a content type like JSON, or some other custom header that's triggering a pre-flight request, which your server may not be handling. Try adding this one, if you're using the ever-common AJAX in your front-end: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requested-With

Gorilla's handlers.CORS() will set sane defaults to get the basics of CORS working for you; however, you can (and maybe should) take control in a more functional manner.

Here's some starter code:

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

答案2

得分: 36

你可以在这里获取更多详细信息:https://stackoverflow.com/questions/20035101/no-access-control-allow-origin-header-is-present-on-the-requested-resource/42744707#42744707 关于这个问题。

还可以尝试使用这个处理程序: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))
}

英文:

You can get more details here: https://stackoverflow.com/questions/20035101/no-access-control-allow-origin-header-is-present-on-the-requested-resource/42744707#42744707 about this issue.

Also try this handler: Go Cors Handler which should solve your issue. I find this much cleaner and easy to resolve the issue.

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

答案3

得分: 21

你应该创建一个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

更多信息:

英文:

You should create a CORSOption object. For example to allow any origin, Use this code:

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

Then you pass this object to your handle.CORS function:

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

For testing it you can use 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

When it works you should see those headers:

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

Final code is here: https://play.golang.org/p/AOrlJsWhvf

More info:

答案4

得分: 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 需要显式地提到,* 不是有效的通配符。典型的 AJAX 库在请求类似 application/json 的内容时会发送 Content-Type,所以也要添加它。
  • * 是 AllowedOrigin 的默认值。
英文:

I realize this is an old issue but nonetheless it took me 30min to get this right.

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

Things to note:

  • AllowedMethods does NOT need to explicitly include OPTIONS, this is part of the CORS handler
  • AllowedHeaders need to be explicitly mentioned, * is not a valid wildcard. Typical ajax libraries will send Content-Type when requesting something like application/json, so add that as well.
  • * is the default for AllowedOrigin

答案5

得分: 6

在声明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))
}

// 访问控制和CORS中间件
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)
    })
}
英文:

After declaring the mux object, add the accessControlMiddleware as a middleware to the declared object.

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

答案6

得分: 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"}, //你的服务可用且允许此基本URL
        AllowedMethods: []string{
            http.MethodGet,    //你的应用程序的HTTP方法
            http.MethodPost,
            http.MethodPut,
            http.MethodPatch,
            http.MethodDelete,
            http.MethodOptions,
            http.MethodHead,
        },
        AllowedHeaders: []string{
            "*",    //或者你可以使用你在应用程序中使用的头键值对
        },
    })

    http.ListenAndServe(":3000", corsOpts.Handler(router))
}
英文:
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))
}

答案7

得分: 4

基于jeremiah.trein的回答。

CORS过滤器是在服务器端设置的。请求在Postman中可能正常工作,但在浏览器中失败,因为Postman不发送预检请求,而浏览器会发送。

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

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

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

代码片段可能如下所示:

router := mux.NewRouter()

// 声明所有路由

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中使用了这段代码(我相信在Flex AppEngine中也可以工作)。

英文:

Base on jeremiah.trein's answer.

CORS filters are set on server side. Request may work with Postman and fail with a browser because Postman doesn't send preflight request whereas a browser does.

Setting the CORS filters will allow you to configure the origins, methods and headers that the backend shall accept.

In addition, if your browser emits POST or PUT requests that contain a json payload (which is quite reasonnable), you'll need to add 'Content-Type' to the allowed headers.

Finally the handlers.CORS()(router) does not only work with the http.ListenAndServe function but also with http.Handle().

The snippet of code might as well look like:

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

It is worth mentionning that i have successfuly used this snippet of code in a Google Cloud Platform Standard AppEngine (and I believe it would work in a Flex AppEngine as well).

答案8

得分: 0

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

AllowAll() *Cors

它可以

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

英文:

The aformentioned package github.com/rs/cors provides a constructor

AllowAll() *Cors

that

> ...create a new Cors handler with permissive configuration allowing all
origins with all standard methods with any header and credentials.

huangapple
  • 本文由 发表于 2016年12月6日 08:40:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/40985920.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定