CORS请求在使用Golang后端时无法正常工作。

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

CORS request with golang backend doesn't works

问题

我正在面临一些实现上的问题。
我有一个用Golang编写的后端和一个UI(使用Angular2),它们在同一台服务器上。

我尝试在后端设置CORS处理,但它仍然不起作用,我不知道原因。

这是我的代码:

package main

import (
	"log"
	"net/http"

	"github.com/gorilla/mux"
	"github.com/rs/cors"
)

var router *mux.Router

func main() {
	router = mux.NewRouter()

	HandleFuncEx("/authentication", handleAuthentication)
	HandleFuncEx("/callA", handleCallA)
	HandleFuncEx("/callB", handleCallB)
	HandleFuncEx("/callC", handleCallC)

	handler := cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
		AllowedMethods: []string{"GET", "POST", "PATCH"},
		AllowedHeaders: []string{"a_custom_header", "content_type"},
	}).Handler(router)
	http.ListenAndServe(":8000", handler)

}

func HandleFuncEx(pattern string, handler func(http.ResponseWriter, *http.Request)) {
	log.Println("handled function", pattern)
	router.HandleFunc(pattern, handler)
}

身份验证模式正常工作(是UI首先调用的),但其他所有调用都失败了预检请求。为什么会这样?

谢谢大家的帮助!

编辑:

这是一个不起作用的响应头示例:

HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Date: Fri, 07 Apr 2017 08:33:12 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8

这些是请求的头部:

OPTIONS /users HTTP/1.1
Host: /* Removed by my company policy */
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: /* Removed by my company policy */
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Access-Control-Request-Headers: access_token
Accept: */*
Referer: /* Removed by my company policy */
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6,it;q=0.4,la;q=0.2
英文:

I'm facing some issue with my implementation.
I have a backend written in Golang and the UI (in Angular2) which are on the same server.

I've tried to set the CORS handling in my backend but it still doesn't work and I'm not getting why.

Here's my code:

package main

import (
	"log"
	"net/http"

	"github.com/gorilla/mux"
	"github.com/rs/cors"
)

var router *mux.Router

func main() {
	router = mux.NewRouter()

	HandleFuncEx("/authentication", handleAuthentication)
	HandleFuncEx("/callA", handleCallA)
	HandleFuncEx("/callB", handleCallB)
	HandleFuncEx("/callC", handleCallC)

	handler := cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
		AllowedMethods: []string{"GET", "POST", "PATCH"},
		AllowedHeaders: []string{"a_custom_header", "content_type"},
	}).Handler(router)
	http.ListenAndServe(":8000", handler)

}

func HandleFuncEx(pattern string, handler func(http.ResponseWriter, *http.Request)) {
	log.Println("handled function", pattern)
	router.HandleFunc(pattern, handler)
}

The authentication pattern works correctly (is the first called by the UI)
all the others calls fails the preflight request.
Why is it happening?

Thanks everybody for the help!

EDIT:

This is an example of a non-working response Headers:

HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Date: Fri, 07 Apr 2017 08:33:12 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8

And these are request's headers:

OPTIONS /users HTTP/1.1
Host: /* Removed by my company policy */
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: /* Removed by my company policy */
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Access-Control-Request-Headers: access_token
Accept: */*
Referer: /* Removed by my company policy */
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6,it;q=0.4,la;q=0.2

答案1

得分: 6

正如Adrian指出的那样,你需要将OPTIONS方法添加到AllowedMethods数组中。

请考虑将AcceptAccept-LanguageContent-Type添加到AllowedHeaders中,这是一个良好的实践。

如果你不想使用github.com/rs/cors包,你可以自己编写一个简单的CORS装饰器中间件,像这样:

CORS装饰器

import (
	"net/http"

	"github.com/gorilla/mux"
)

// CORSRouterDecorator将CORS头应用于mux.Router
type CORSRouterDecorator struct {
	R *mux.Router
}

// ServeHTTP包装HTTP服务器,启用CORS头。
// 有关CORS的更多信息,请访问https://www.w3.org/TR/cors/
func (c *CORSRouterDecorator) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	if origin := req.Header.Get("Origin"); origin != "" {
		rw.Header().Set("Access-Control-Allow-Origin", origin)
		rw.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
		rw.Header().Set("Access-Control-Allow-Headers", "Accept, Accept-Language, Content-Type, YourOwnHeader")
	}
	// 如果是预检请求(Preflighted OPTIONS request),则在此停止
	if req.Method == "OPTIONS" {
		return
	}

	c.R.ServeHTTP(rw, req)
}

HTTP服务器

r := mux.NewRouter()
r.Handle("/authentication", handleAuthentication)

http.Handle("/", &CORSRouterDecorator{r})

et voilà.

英文:

As Adrian pointed out, you need to add the OPTIONS Method to the AllowedMethods array.

Please also consider to add Accept, Accept-Language and Content-Type to the AllowedHeaders as good practice.

If you don't want to use the github.com/rs/cors package, you can write a simple CORS decorator middleware on your own like this:

CORS decorator

import (
	"net/http"

	"github.com/gorilla/mux"
)

// CORSRouterDecorator applies CORS headers to a mux.Router
type CORSRouterDecorator struct {
	R *mux.Router
}

// ServeHTTP wraps the HTTP server enabling CORS headers.
// For more info about CORS, visit https://www.w3.org/TR/cors/
func (c *CORSRouterDecorator) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	if origin := req.Header.Get("Origin"); origin != "" {
		rw.Header().Set("Access-Control-Allow-Origin", origin)
		rw.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
		rw.Header().Set("Access-Control-Allow-Headers", "Accept, Accept-Language, Content-Type, YourOwnHeader")
	}
	// Stop here if its Preflighted OPTIONS request
	if req.Method == "OPTIONS" {
		return
	}

	c.R.ServeHTTP(rw, req)
}

HTTP server

r := mux.NewRouter()
r.Handle("/authentication", handleAuthentication)

http.Handle("/", &CORSRouterDecorator{r})

et voilà.

答案2

得分: 1

我使用Negroni作为中间件,并使用以下代码:

func main() {

    c := cors.New(cors.Options{
        AllowedOrigins: []string{"*"},
        AllowedMethods: []string{"POST", "GET", "OPTIONS", "PUT", "DELETE"},
        AllowedHeaders: []string{"Accept", "content-type", "Content-Length", "Accept-Encoding", "X-CSRF-Token", "Authorization"},
    })

    router := mux.NewRouter()
    router = routers.SetAuthRoute(router)

    apiRoutes := routers.InitRoutes()

    router.PathPrefix("/api").Handler(negroni.New(
        negroni.HandlerFunc(controllers.ValidateTokenMiddleware),
        negroni.Wrap(apiRoutes),
    ))

    server := negroni.Classic()
    server.Use(c)
    server.UseHandler(router)
    server.Run("0.0.0.0:" + os.Getenv("PORT"))
}

这段代码使用了Negroni作为中间件,并设置了CORS选项。它创建了一个路由器,并设置了身份验证路由。然后,它将API路由包装在Negroni中间件中,并将其与路由器绑定。最后,它创建了一个Negroni服务器,并将CORS中间件和路由器绑定到服务器上,并在指定的端口上运行服务器。

英文:

I use Negroni as middleware and this code:

func main() {

	c := cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
		AllowedMethods: []string{"POST", "GET", "OPTIONS", "PUT", "DELETE"},
		AllowedHeaders: []string{"Accept", "content-type", "Content-Length", "Accept-Encoding", "X-CSRF-Token", "Authorization"},
	})

	router := mux.NewRouter()
	router = routers.SetAuthRoute(router)

	apiRoutes := routers.InitRoutes()

	router.PathPrefix("/api").Handler(negroni.New(
		negroni.HandlerFunc(controllers.ValidateTokenMiddleware),
		negroni.Wrap(apiRoutes),
	))

	server := negroni.Classic()
	server.Use(c)
	server.UseHandler(router)
	server.Run("0.0.0.0:" + os.Getenv("PORT"))
}

答案3

得分: 1

与其他两个回答类似,但是在我的情况下,我的项目托管在cloud9上,所以我需要进行一些调整。

这是我添加的代码:

cor := cors.New(cors.Options{
    AllowedOrigins:   []string{"https://*.c9users.io", "http://myapp.c9users.io:8080", "https://*.c9.io"},
    AllowedMethods:   []string{"POST", "GET", "OPTIONS", "PUT"},
    AllowedHeaders:   []string{"Accept", "Accept-Language", "Content-Type"},
    AllowCredentials: true,
    Debug:            true,
});

我不得不添加额外的http来源,因为Safari使用http而不是https进行初始的options请求。

搞定了。

英文:

Similar to the other two responses, but I my case my project is hosted on cloud9 so I had a couple of tweaks to do.

This is the code i added:

	cor := cors.New(cors.Options{
		AllowedOrigins:   []string{"https://*.c9users.io", "http://myapp.c9users.io:8080", "https://*.c9.io"},
		AllowedMethods:   []string{"POST", "GET", "OPTIONS", "PUT"},
		AllowedHeaders:   []string{"Accept", "Accept-Language", "Content-Type"},
		AllowCredentials: true,
		Debug:            true,
	});

I had to add the extra http origin as Safari makes the initial options request using http instead of https.

Sorted.

huangapple
  • 本文由 发表于 2017年4月5日 21:20:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/43232463.html
匿名

发表评论

匿名网友

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

确定