Echo CORS with/ Proxy middlewares causes problems with/ Access-Allow-Origins response header
Echo CORS w/ Proxy middlewares causes problems w/ Access-Allow-Origins response header
我正在使用 LabStack 的 Golang Echo 框架构建服务。
其中一个路由需要代理后端服务的请求和响应。
但我也需要 CORS 来处理此服务。
所以我在 request/response 堆栈中使用 middleware.CORSWithConfig
和 middleware.ProxyWithConfig
。
我发现 Access-Control-Allow-Origins
header 有一些奇怪之处,其中 header 的值在代理服务对我的 Echo 服务器 *
的响应中,但是一旦它通过代理,它就会在返回到客户端时变为 *, *
。
我开始看到以下与 CORS 违规相关的浏览器错误:
VM1627:362 Access to XMLHttpRequest at 'http://localhost:6273/' from origin 'http://localhost:8002' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.
有人遇到过这个吗?任何人都知道为什么会发生这种情况,也许有解决办法?
下面是一些示例代码:
package main
func singleTargetBalancer(url *url.URL) middleware.ProxyBalancer {
targetURL := []*middleware.ProxyTarget{
{
URL: url,
},
}
return middleware.NewRoundRobinBalancer(targetURL)
}
func Noop(ctx echo.Context) (err error) {
ctx.String(
http.StatusNotImplemented,
"No op handler should never be reached!",
)
return err
}
func main() {
e := echo.New()
e.HideBanner = true
e.Use(
middleware.CORSWithConfig(middlewares.CustomCorsConfig),
middlewares.ThriftMetrics(),
)
// Have to use a Noop handler since we're not trying to set up a full-on proxy for the backend service. We only want this one route to be proxied.
e.POST(
"/",
handlers.Noop,
middleware.ProxyWithConfig(middleware.ProxyConfig{
Balancer: singleTargetBalancer("[backend service URL]"),
})
)
}
我最终通过编写自定义 Echo 中间件来解决这个问题,以便在 Echo 的代理中间件可以将 headers 发送回客户端之前挂接到响应。
func setResponseACAOHeaderFromRequest (req http.Request, resp echo.Response) {
resp.Header().Set(echo.HeaderAccessControlAllowOrigin,
req.Header.Get(echo.HeaderOrigin))
}
func ACAOHeaderOverwriteMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
ctx.Response().Before(func() {
setResponseACAOHeaderFromRequest(*ctx.Request(), *ctx.Response())
})
return next(ctx)
}
}
然后把这个中间件放在e.Use()
右边你的代理中间件之前:
e.POST(
"/",
handlers.Noop,
ACAOHeaderOverwriteMiddleware,
middleware.ProxyWithConfig(middleware.ProxyConfig{
Balancer: singleTargetBalancer("[backend service URL]"),
})
)
Echo Request::Before()
挂钩的文档:https://echo.labstack.com/guide/response#before-response
我正在使用 LabStack 的 Golang Echo 框架构建服务。
其中一个路由需要代理后端服务的请求和响应。
但我也需要 CORS 来处理此服务。
所以我在 request/response 堆栈中使用 middleware.CORSWithConfig
和 middleware.ProxyWithConfig
。
我发现 Access-Control-Allow-Origins
header 有一些奇怪之处,其中 header 的值在代理服务对我的 Echo 服务器 *
的响应中,但是一旦它通过代理,它就会在返回到客户端时变为 *, *
。
我开始看到以下与 CORS 违规相关的浏览器错误:
VM1627:362 Access to XMLHttpRequest at 'http://localhost:6273/' from origin 'http://localhost:8002' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.
有人遇到过这个吗?任何人都知道为什么会发生这种情况,也许有解决办法?
下面是一些示例代码:
package main
func singleTargetBalancer(url *url.URL) middleware.ProxyBalancer {
targetURL := []*middleware.ProxyTarget{
{
URL: url,
},
}
return middleware.NewRoundRobinBalancer(targetURL)
}
func Noop(ctx echo.Context) (err error) {
ctx.String(
http.StatusNotImplemented,
"No op handler should never be reached!",
)
return err
}
func main() {
e := echo.New()
e.HideBanner = true
e.Use(
middleware.CORSWithConfig(middlewares.CustomCorsConfig),
middlewares.ThriftMetrics(),
)
// Have to use a Noop handler since we're not trying to set up a full-on proxy for the backend service. We only want this one route to be proxied.
e.POST(
"/",
handlers.Noop,
middleware.ProxyWithConfig(middleware.ProxyConfig{
Balancer: singleTargetBalancer("[backend service URL]"),
})
)
}
我最终通过编写自定义 Echo 中间件来解决这个问题,以便在 Echo 的代理中间件可以将 headers 发送回客户端之前挂接到响应。
func setResponseACAOHeaderFromRequest (req http.Request, resp echo.Response) {
resp.Header().Set(echo.HeaderAccessControlAllowOrigin,
req.Header.Get(echo.HeaderOrigin))
}
func ACAOHeaderOverwriteMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
ctx.Response().Before(func() {
setResponseACAOHeaderFromRequest(*ctx.Request(), *ctx.Response())
})
return next(ctx)
}
}
然后把这个中间件放在e.Use()
右边你的代理中间件之前:
e.POST(
"/",
handlers.Noop,
ACAOHeaderOverwriteMiddleware,
middleware.ProxyWithConfig(middleware.ProxyConfig{
Balancer: singleTargetBalancer("[backend service URL]"),
})
)
Echo Request::Before()
挂钩的文档:https://echo.labstack.com/guide/response#before-response