在Go Gin API中拒绝多个CORS值。

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

multiple CORS values being rejected in Go gin api

问题

在我的Go API中,我正在使用gin,并且在我的Access-Control-Allow-Origin头部中设置了一个值。如果我设置了多个值,我的React UI会抛出一个错误,内容为The Access-Control-Allow-Origin header contains multiple values 'http://value1, http://value2', but only one is allowed...。我需要设置多个值。我该如何做?

这个API是一个反向代理,以下是相关的代码:

func proxy(c *gin.Context) {
  var remote = "myUrl"
  proxy := httputil.NewSingleHostReverseProxy(remote)
  proxy.Director = func(req *http.Request) {
		req.Header.Set("Authorization", "My Auth Values")
		req.Host = remote.Host
		req.URL.Scheme = remote.Scheme
		req.URL.Host = remote.Host
	}
	proxy.ModifyResponse = addCustomHeader
	proxy.ServeHTTP(c.Writer, c.Request)
}

func addCustomHeader(r *http.Response) error {
	r.Header["Access-Control-Allow-Origin"] = []string{"value1;"}
	return nil
}
英文:

In my Go API, I'm using gin, and I have one value set in my Access-Control-Allow-Origin header. If I have more than one, my react UI throws an error to the effect of The Access-Control-Allow-Origin header contains multiple values 'http://value1, http://value2', but only one is allowed.... I need to set multiple values. How do I do this?

The API is a reverse proxy, and here's the relevant code:

func proxy(c *gin.Context) {
  var remote = "myUrl"
  proxy := httputil.NewSingleHostReverseProxy(remote)
  proxy.Director = func(req *http.Request) {
		req.Header.Set("Authorization", "My Auth Values")
		req.Host = remote.Host
		req.URL.Scheme = remote.Scheme
		req.URL.Host = remote.Host
	}
	proxy.ModifyResponse = addCustomHeader
	proxy.ServeHTTP(c.Writer, c.Request)
}

func addCustomHeader(r *http.Response) error {
	r.Header["Access-Control-Allow-Origin"] = []string{"value1"}
	return nil
}

</details>


# 答案1
**得分**: 2

CORS头部只能包含一个值。如果你想要实现自己的CORS中间件,你需要绕过这个限制。

一个简单的CORS中间件会添加`Access-Control-Allow-Origin`头部,其值为传入请求的特定地址,通常从`Referer`或`Origin`头部获取。通常,你会先将这个地址与一个列表或映射进行匹配,以查看它是否在你的"允许列表"中。如果是的话,请求的地址就会被添加为允许的来源(作为一个单独的值)。

一个简单的示例可能如下所示:

```go
allowList := map[string]bool{
	"https://www.google.com": true,
	"https://www.yahoo.com":  true,
}

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
	if origin := r.Header.Get("Origin"); allowList[origin] {
		w.Header().Set("Access-Control-Allow-Origin", origin)
	}
})

由于你正在使用反向代理,你可以从响应中访问请求。

mod := func(allowList map[string]bool) func(r *http.Response) error {
	return func(r *http.Response) error {
		if origin := r.Request.Header.Get("Origin"); allowList[origin] {
			r.Header.Set("Access-Control-Allow-Origin", origin)
		}
		return nil
	}
}

proxy := &httputil.ReverseProxy{
	Director: func(r *http.Request) {
		r.URL.Scheme = "https"
		r.URL.Host = "go.dev"
		r.Host = r.URL.Host
	},
	ModifyResponse: mod(allowList),
}
英文:

A CORS header can only contain a single value. If you want to implement your own CORS middleware, you need to work around that fact.

A simple CORS middleware will add the Access-Control-Allow-Origin header with the value of the specific address of the incoming request, usually taken from the Referer or Origin header. Typically, you match this against a list or map first, to see if it's in your allow list. If so, then the address of the request is added as allowed origin (as a single value).

A simple example could look like this

allowList := map[string]bool{
	&quot;https://www.google.com&quot;: true,
	&quot;https://www.yahoo.com&quot;:  true,
}

http.HandleFunc(&quot;/&quot;, func(w http.ResponseWriter, r *http.Request) {
	if origin := r.Header.Get(&quot;Origin&quot;); allowList[origin] {
		w.Header().Set(&quot;Access-Control-Allow-Origin&quot;, origin)
	}
})

Since you are using the reverse proxy, you can access the request from the response.

mod := func(allowList map[string]bool) func(r *http.Response) error {
	return func(r *http.Response) error {
		if origin := r.Request.Header.Get(&quot;Origin&quot;); allowList[origin] {
			r.Header.Set(&quot;Access-Control-Allow-Origin&quot;, origin)
		}
		return nil
	}
}

proxy := &amp;httputil.ReverseProxy{
	Director: func(r *http.Request) {
		r.URL.Scheme = &quot;https&quot;
		r.URL.Host = &quot;go.dev&quot;
		r.Host = r.URL.Host
	},
	ModifyResponse: mod(allowList),
}

答案2

得分: 1

每个传入请求只需要一个值。通常的做法是在服务器上配置受信任的来源,例如:

  • trustedOrigins: [https://www.domain1.com, https://www.domain2.com]

然后检查由所有现代浏览器发送的origin头的运行时值。如果这是一个受信任的来源,那么添加CORS头:

可以使用通配符,但这不被推荐,而且如果您还使用带有cookie的凭证请求(例如),它也无法按预期工作。

英文:

You only need a single value for each incoming request. The usual technique is to configure trusted origins on the server, eg:

  • trustedOrigins: [https://www.domain1.com, https://www.domain2.com]

Then check the runtime value of the origin header, which is sent by all modern browsers. If this is a trusted origin then add CORS headers:

A wildcard could be used but that is not recommended and also will not work as intended if you are also using credentialed requests (eg those with cookies).

huangapple
  • 本文由 发表于 2022年2月8日 04:56:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/71025292.html
匿名

发表评论

匿名网友

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

确定